0

这就是我一直试图解决的问题。鉴于:

  • a) 产品图片。预计全彩
  • b) 该图像的掩码:RGBA(0,0,0,0) 表示忽略,RGBA(255,255,255,255) 表示替换
  • c) 合成图像:这是与蒙版合成的

想法是将蒙版与合成图像合成,这将导致所有白色像素成为合成像素,但透明像素保持透明。这最终覆盖在产品图像的顶部,仅有效地转换了遮罩区域中的像素。

我有这个完美的工作,除了一个小问题。每次通过我的 Composite 函数似乎都会将输出缩小 0.5 倍。

我的解决方案中有一些代码,所以我会发布我认为必要的内容,但请随时提出更多要求。

这是我的复合方法:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
using GL = OpenTK.Graphics.OpenGL.GL;
using HintMode = OpenTK.Graphics.OpenGL.HintMode;
using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using PixelType = OpenTK.Graphics.OpenGL.PixelType;
using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
using Utilities = OpenTK.Platform.Utilities;

namespace SpriteSheetMaker
{
public static class ImageBlender
{

    static DebugLogger logger = DebugLogger.GetInstance(@"debug.txt");
    //Mask should be white where replacing, and transparent elsewhere
    public static TexturedPolygon Composite(TexturedPolygon __baseImage, TextureBlendItem item, int level = 1)
    {

        var oldScale = OpenGLHelpers.Scale.Clone();
        var oldSize = OpenGLHelpers.Canvas.Size;
        var newSize = __baseImage.Texture2D.Texture2D.Size;


        logger.WriteLine("Composite Requested. Mask Details: " + __baseImage.Rotation + " --- " + __baseImage.Scale + " --- " + __baseImage.Translation);
        OpenGLHelpers.ClearScreen();
        var _baseImage = __baseImage.Clone();
        _baseImage.Texture2D.Texture2D.Save("composite_test_base" + level + ".png");
        var _mask = item.Mask.Clone();
        var _composite = item.Composite.Clone();


      logger.WriteLine("Composite Requested. Mask Details: " + __baseImage.Rotation + " --- " + __baseImage.Scale + " --- " + __baseImage.Translation);  

        _mask.ResetTransform();
        _composite.ResetTransform();
        _baseImage.ResetTransform();


        GL.Enable(EnableCap.Blend);

        // render the mask
        _mask.Draw();

        //Blend the composite
        GL.Disable(EnableCap.Blend);
        GL.Enable(EnableCap.Blend);
        GL.BlendEquation(BlendEquationMode.Min);
        _composite.Draw();
        GL.Disable(EnableCap.Blend); ;

        //Not sure exactly what this does
        GL.Enable(EnableCap.Blend);
        GL.BlendEquation(BlendEquationMode.FuncAdd);


        //Grab the composite and save it into a variable, because we are clearing the screen now
        var bmp = OpenGLHelpers.GrabScreenshot(oldSize);
        var _composite_2 = new BaseTextureImage(bmp).GetDrawable();
        _composite_2.ResetTransform();


        //Now we have the composited mask, we can simply draw it over the original image
        OpenGLHelpers.ClearScreen();
        _baseImage.Draw();
        _composite_2.Draw();


        bmp = OpenGLHelpers.GrabScreenshot(oldSize);


        //    OpenGLHelpers.Canvas.Resize(oldSize);
        return new BaseTextureImage(bmp).GetDrawable();

    }


    public static TexturedPolygon Composite(TexturedPolygon _baseImage, List<TextureBlendItem> blends)
    {
        TexturedPolygon rtn = _baseImage.Clone();
        bool doScaleFix = true;
        int idx = 0;
        foreach(var blend in blends)
        {
            var c = Composite(rtn, blend, (idx+1));
            c.Texture2D.Texture2D.Save("composite_test_" + idx + ".png");
            c.Scale = _baseImage.Scale;
            c.Rotation = _baseImage.Rotation;
            c.Translation = _baseImage.Translation;
            rtn = c;
            doScaleFix = false;
            idx++;
        }
        return rtn;
    }



    }
}

这是 TexturedPolygon 类

            using System;
            using System.Collections.Generic;
            using System.Drawing;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using OpenTK;
            using OpenTK.Graphics;
            using OpenTK.Graphics.OpenGL;
            using OpenTK.Platform;
            using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
            using GL = OpenTK.Graphics.OpenGL.GL;
            using HintMode = OpenTK.Graphics.OpenGL.HintMode;
            using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
            using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
            using PixelFormat = System.Drawing.Imaging.PixelFormat;
            using PixelType = OpenTK.Graphics.OpenGL.PixelType;
            using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
            using Utilities = OpenTK.Platform.Utilities;
            using System.Drawing.Imaging;
            using System.Reflection;

            namespace SpriteSheetMaker
            {
                public class TexturedPolygon : BasePolygon
                {

                    public BaseTextureImage Texture2D { get; set; }


                    public TexturedPolygon(BaseTextureImage texture, List<Vector3> pts) : base(pts)
                    {
                        Texture2D = texture;
                    }
                    public new TexturedPolygon Clone()
                    {
                        TexturedPolygon polygon = new TexturedPolygon(Texture2D, Vertices);
                        polygon.FillColor = this.FillColor.Clone();
                        polygon.EdgeColor = this.EdgeColor.Clone();
                        polygon.EdgeWidth = this.EdgeWidth;
                        polygon.Translation = this.Translation.Clone();
                        polygon.Rotation = this.Rotation.Clone();
                        polygon.Scale = this.Scale.Clone();
                        return polygon;

                    }
                    public TexturedPolygon(List<Vector3> pts) : base(pts)
                    {

                    }

                    public override void _draw()
                    {
                        if (Texture2D == null)
                        {
                            GL.ClearColor(Color.Transparent);
                            GL.Enable(EnableCap.Blend);
                            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                            this._basePolygonDraw();
                            return;
                        }

                        var bb = NoTransformBoundingBox();
                        GL.ClearColor(Color.Transparent);
                        GL.BindTexture(TextureTarget.Texture2D, Texture2D.TextureID);
                        GL.Enable(EnableCap.Texture2D);
                        GL.Enable(EnableCap.Blend);
                        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                        GL.Begin(PrimitiveType.Polygon);
                        for(int i = 0; i < Vertices.Count; i++)
                        {
                            var pt = Vertices[i];
                            var fillColor = GetVertexFillColor(i);
                            var alpha = fillColor.Alpha;
                            GL.Color4(1.0, 1.0, 1.0, alpha);
                            var texX = (pt.X - (float)bb.Left) / (bb.Right - (float)bb.Left);
                            var texY = (pt.Y - (float)bb.Top) / (bb.Bottom - (float)bb.Top);
                            GL.TexCoord2(texX, texY);
                            GL.Vertex2(pt.X, pt.Y);
                        }
                        GL.End();

                       // GL.Disable(EnableCap.Texture2D);
                    }
                }
            }

这是 BasePolygon 类:

            using System;
            using System.Collections.Generic;
            using System.Drawing;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using OpenTK;
            using OpenTK.Graphics;
            using OpenTK.Graphics.OpenGL;
            using OpenTK.Platform;
            using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
            using GL = OpenTK.Graphics.OpenGL.GL;
            using HintMode = OpenTK.Graphics.OpenGL.HintMode;
            using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
            using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
            using PixelFormat = System.Drawing.Imaging.PixelFormat;
            using PixelType = OpenTK.Graphics.OpenGL.PixelType;
            using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
            using Utilities = OpenTK.Platform.Utilities;

            namespace SpriteSheetMaker
            {
                public class BasePolygon : BaseTexture
                {
                    protected List<Vector3> Vertices = new List<Vector3>();
                    public GeometryColor FillColor = new GeometryColor();
                    public GeometryColor EdgeColor = new GeometryColor();

                    public float EdgeWidth = 1.0f;
                    public List<Vector3> CurrentVertices
                    {
                        get
                        {
                            return Vertices.ToList();
                        }
                    }
                    Point[] _points
                    {
                        get
                        {
                            return Vertices.Select(x => x.ToPoint()).ToArray();
                        }
                    }
                    protected override List<Vector3> GetPolygonPoints()
                    {
                        List<Vector3> rtn = new List<Vector3>();
                        foreach(var pt in Vertices)
                        {
                            rtn.Add(pt.Clone());
                        }
                        return rtn;
                    }
                    protected void AlignToOrigin()
                    {
                        var ctr = NoTransformCenter();
                        for(int i = 0; i < Vertices.Count; i++)
                        {
                            var pt = Vertices[i];
                            pt = pt.Subtract(ctr);
                            Vertices[i] = pt;

                        }
                        Translation = ctr.Clone();
                    }
                    protected void AlignToCenter()
                    {
                        var ctr = NoTransformCenter();
                        for (int i = 0; i < Vertices.Count; i++)
                        {
                            var pt = Vertices[i];
                            pt = pt.Add(Translation);
                            Vertices[i] = pt;

                        }
                        Translation = Vector3.ZERO;
                    }
                    public static BasePolygon ClonePolygon(BasePolygon poly)
                    {
                        return poly.Clone();
                    }
                    public BasePolygon Clone()
                    {
                        BasePolygon polygon = new BasePolygon();
                        polygon.Vertices = this.CurrentVertices;
                        polygon.FillColor = this.FillColor.Clone();
                        polygon.EdgeColor = this.EdgeColor.Clone();
                        polygon.EdgeWidth = this.EdgeWidth;
                        polygon.Translation = this.Translation.Clone();
                        polygon.Rotation = this.Rotation.Clone();
                        polygon.Scale = this.Scale.Clone();
                        return polygon;
                    }
                    public BasePolygon(List<Vector3> pts)
                    {
                        AddVertexes(pts);
                        AlignToOrigin();
                    }
                    public BasePolygon(params Vector3[] pts)
                    {
                        AddVertexes(pts.ToList());
                        AlignToOrigin();
                    }
                    protected void AddVertex(Vector3 pt)
                    {
                        Vertices.Add(pt.Clone());
                    }
                    protected void AddVertexes(IEnumerable<Vector3> pts)
                    {
                        pts.ToList().ForEach(x =>
                        {
                            AddVertex(x);
                        });
                    }
                    protected void RemoveVertex(Vector3 pt)
                    {
                        Vertices.Remove(pt);
                    }
                    protected void RemoveVertexes(IEnumerable<Vector3> pts)
                    {
                        pts.ToList().ForEach(x =>
                        {
                            RemoveVertex(x);
                        });
                    }

                    public override void _draw()
                    {
                        this._basePolygonDraw();
                    }

                    public ColorLibrary.sRGB GetVertexFillColor(int index)
                    {
                        var pct = ((float)index + 1.0f) / (float)Vertices.Count;
                        var colorIdx = (int)((FillColor.Colors.Count - 1.0f) * pct);
                        return  FillColor.Colors[colorIdx];
                    }
                    public ColorLibrary.sRGB GetVertexEdgeColor(int index)
                    {
                        var pct = ((float)index + 1.0f) / (float)Vertices.Count;
                        var colorIdx = (int)Math.Round((float)(EdgeColor.Colors.Count - 1.0f) * pct);
                        return EdgeColor.Colors[colorIdx];
                    }

                    protected void _basePolygonDraw()
                    {
                        this.wireframe();
                        this.fill();           
                    }
                    private void wireframe()
                    {
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
                        GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
                        var pts = Vertices;
                        ColorLibrary.sRGB color1;
                        ColorLibrary.sRGB color2;
                        GL.Begin(PrimitiveType.Lines);

                        for (var i = 0; i < pts.Count; i++)
                        {
                            var idx2 = (i + 1) % pts.Count;

                            color1 = GetVertexEdgeColor(i);
                            color2 = GetVertexEdgeColor(idx2);

                            var a = pts[i];
                            var b = pts[idx2];
                            GL.Color4(color1.R, color1.G, color1.B, color1.Alpha);
                            GL.Vertex3(a.OpenTKVector);
                            GL.Color4(color2.R, color2.G, color2.B, color2.Alpha);
                            GL.Vertex3(b.OpenTKVector);
                        }

                        GL.End();
                    }
                    private void fill()
                    {
                        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
                        GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                        var pts = Vertices;
                        ColorLibrary.sRGB color;
                        GL.Begin(PrimitiveType.Polygon);
                        for(int i = 0; i < pts.Count; i++)
                        {
                            color = GetVertexFillColor(i);
                            var pt = pts[i];
                             GL.Color4(color.R, color.G, color.B, color.Alpha);
                            GL.Vertex3(pt.OpenTKVector);
                        }

                        GL.End();


                    }

                }
            }

这是 BaseTexture 类

            using ....

            namespace SpriteSheetMaker
            {
                public abstract class BaseTexture
                {
                    protected static Random rnd = new Random();

                    public Vector3 Translation = new Vector3(0, 0, 0);
                    public Vector3 Scale = new Vector3(1, 1, 1);
                    public Vector3 Rotation = new Vector3(0, 0, 0);
                    public Vector3 Velocity = new Vector3(0, 0, 0);
                    public void ResetTransform()
                    {
                        Translation = Vector3.ZERO;
                        Scale = Vector3.ONE;
                        Rotation = Vector3.ZERO;
                    }
                    private Guid _guid = Guid.NewGuid();
                    public Guid Guid
                    {
                        get
                        {
                            return _guid;
                        }
                        private set
                        {
                            _guid = value;
                        }
                    }
                    public bool DrawBounds = false;

                    public enum CollisionDirection
                    {
                        None = 0,
                        Up = 1,
                        Right = 2,
                        Down = 3,
                        Left = 4
                    }
                    public RectangleF NoTransformBoundingBox()
                    {
                        var poly = GetPolygonPoints();
                        var rect = Utility.PointsToRectangle(poly);
                        return rect;
                    }
                    protected abstract List<Vector3> GetPolygonPoints();

                    public Vector3 NoTransformCenter()
                    {
                        var poly = GetPolygonPoints();
                        var ctr = Vector3.Average(poly);
                        return ctr;
                    }

                    protected virtual RectangleF NonRotatedBoundingBox()
                    {
                        var polyPts = GetPolygonPoints();

                        foreach (var p in polyPts)
                        {
                            p.X = (Translation.X + Scale.X * p.X);
                            p.Y = (Translation.Y + Scale.Y * p.Y);
                        }

                        var rect = Utility.PointsToRectangle(polyPts);
                        return rect;
                    }
                    public RectangleF BoundingBox()
                    {
                        if(this.Rotation.Z == 0)
                        {
                            return NonRotatedBoundingBox();
                        }
                        return RotatedBoundingBox();


                    }

                    private RectangleF RotatedBoundingBox()
                    {

                        var polyPts = GetPolygonPoints();

                        foreach(var p in polyPts)
                        {
                            p.X = Translation.X + Scale.X*p.X; 
                            p.Y = Translation.Y + Scale.Y*p.Y;
                        }
                        var ctr = this.Center();
                        var theta = this.Rotation.Z;

                        var ptsRotated = Utility.RotatePoints(polyPts, ctr, theta);
                        var bb = Utility.GetBoundsFromPoints(ptsRotated);

                        var rotated = new RectangleF(bb.Left, bb.Top, bb.Width, bb.Height);

                        return rotated;
                    }

                    public bool IsColliding(BaseTexture tex)
                    {
                        var bb = this.BoundingBox();
                        var bb2 = tex.BoundingBox();
                        return RectangleF.Intersect(bb, bb2) != RectangleF.Empty;
                    }

                    public CollisionDirection CollisionSide(BaseTexture tex)
                    {
                        var isColliding = IsColliding(tex);
                        if (!isColliding)
                        {
                            return CollisionDirection.None;
                        }
                        var ctrThis = this.Center();
                        var ctrThat = tex.Center();

                        var angleTo = ctrThis.AngleTo(ctrThat);
                        var pi = Math.PI;
                        var two_pi = 2*pi;
                        var pi_over_2 = pi/2.0;
                        var pi_over_4 = pi/4.0;

                        //0 to 45
                        if (angleTo >= 0 && angleTo <= pi_over_4)
                        {
                            return CollisionDirection.Right;
                        }
                        //45 to 135
                        else if (angleTo >= pi_over_4 && angleTo <= (pi_over_4) + (pi_over_2))
                        {
                            return CollisionDirection.Down;
                        }
                        //135 to 225
                        else if (angleTo >= (pi_over_4) + (pi_over_2) && angleTo <= (pi) + (pi_over_4))
                        {
                            return CollisionDirection.Left;
                        }
                        //225 to 315
                        else if (angleTo >= (pi) + (pi_over_4) && angleTo <= two_pi - pi_over_4)
                        {
                            return CollisionDirection.Up;
                        }
                        //315 to 360
                        else if (angleTo >= two_pi - pi_over_4 && angleTo <= two_pi)
                        {
                            return CollisionDirection.Right;
                        }
                        else
                        {
                            return CollisionDirection.None;
                        }
                    }

                    public Vector3 Center()
                    {
                        return NoTransformCenter().Add(this.Translation);
                    }

                    public float NoTransformRadius
                    {
                        get
                        {
                            var bb = NoTransformBoundingBox();
                            return (float)(Math.Max(bb.Width, bb.Height));
                        }
                    }

                    public float Radius
                    {
                        get
                        {
                            var bb = BoundingBox();
                            return (float)(Math.Max(bb.Width, bb.Height));
                        }
                    }

                    public abstract void _draw();

                    protected void _draw_bounds()
                    {
                        var bb = BoundingBox();
                        var ctr = Utility.RectangleCenter(bb);
                        var ctr2 = this.Center();
                        RectanglePolygon rec = RectanglePolygon.Create(ctr, bb.Width, bb.Height);
                        var fillColor = new ColorLibrary.sRGB(1,1,1);
                        fillColor.Alpha = 0.0;
                        rec.FillColor.SetSolid(fillColor);
                        rec.EdgeColor.SetSolid(new ColorLibrary.sRGB(1,0,0));
                        rec.Draw();
                    }
                    public virtual void Draw()
                    {
                        GL.ClearColor(Color.Transparent);

                        if (this.DrawBounds)
                        {
                            this._draw_bounds();
                        }

                        var ctr = NoTransformCenter();
                        OpenGLHelpers.RotationPivot = ctr;
                        OpenGLHelpers.AddTransform(Rotation,Scale,Translation);
                        OpenGLHelpers.ApplyTransforms();
                        _draw();
                        OpenGLHelpers.SubtractTransform(Rotation,Scale,Translation);
                        GL.PopMatrix();
                      //  GL.Flush();
                    }
                    public override bool Equals(object obj)
                    {
                        var o = obj as BaseTexture;
                        return o.Guid == Guid;
                    }

                }
            }

如果您需要更多代码,例如 OpenGLHelpers 内部的方法,我可以提供。请记住,通常我的绘图代码有效。我没有在这里设置任何投影,所以这就是我重置变换的原因。无论如何,平移和旋转现在都为零,因此实际上只是重置比例。我的基本绘图方法从 [0,1] 标准化,并且比例是将图像拉伸到所需的任何尺寸。

此外,这就是我所说的规模变得混乱的意思。那个红色的烧瓶形状应该是完全覆盖了烧瓶的内部,而且,烧瓶本身也被缩小了!所以它缩水了一倍...

复合失败

这显示了通过 4 次通过的迭代。笑脸是添加的另一个面具/复合组合

基础图片: 基本图像

面具 1: 面具 1

复合1: 复合 1

感谢任何帮助的人

4

1 回答 1

0

我让它工作了!

所以有2个问题。

  • 我使用 -0.5 到 0.5 作为我的域范围,而 -1 到 1 更合适
  • 我还遇到了其他问题,例如需要确保我的所有纹理实际上都在视口中,并调整 glControl 的大小以适应产品纹理

    终于工作了

于 2016-03-05T22:44:21.743 回答