2016-03-05 3 views
0

Итак, вот проблема, которую я пытался решить. При использовании:У меня есть Image Compositing (белая/альфа-маска), работающая в OpenTK/C#, за исключением того, что каждый проход через шкалы выводит вывод

  • a) Изображение продукта. Ожидается, что полный цвет
  • б) маска этого образа: RGBA (0,0,0,0) означает игнорировать, RGBA (255255255255) означает замену
  • с) составное изображение: Это смешан с маской

Идея состоит в объединении маски с композитным изображением, что приведет к тому, что все белые пиксели станут составными пикселями, но прозрачные пиксели остаются прозрачными. Это, наконец, накладывается поверх изображения продукта, эффективно трансформируя только пиксели в области маски.

У меня это работает отлично, за исключением одной маленькой проблемы. Каждый проход через мою функцию 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], а масштаб - это то, что растягивает изображение до любых желаемых размеров.

Кроме того, вот что я имею в виду, когда весы перепутались. Предполагается, что эта форма в виде красной колбы должна покрыть внутреннюю часть колбы, а также, чтобы сама колба упала! Так что двойное сжался ...

Composite Fail

Это показывает итерации через 4 прохода проходных. В смайликов были еще маска/композитный комбо добавлен

Base Image: Base Image

Маска 1: Mask 1

Композитный 1: Composite 1

Спасибо тому, кто помогает

+0

Ok Я на somethnig. Итак, все мои полигональные классы ae сосредоточены вокруг начала координат. Поэтому у меня есть {-0.5, -0.5}, {0.5, -0.5}, {0.5, 0.5}, {-0.5, 0.5}. Когда я привязывал свои полигоны от 0 до 1, это в значительной степени работает. Я действительно хочу сохранить свои полигоны в диапазоне от -0,5 до 0,5, хотя ......... – applejacks01

ответ

0

Я заработал!

Таким образом, было 2 проблемы.

  • Я использую -0.5 до 0.5 в качестве моего диапазона домена, когда -1 до 1 был более подходящим
  • У меня также были различные вопросы, такие как необходимость убедиться, что все мои текстуры были на самом деле в окно просмотра и изменения размера glControl, чтобы соответствовать структуры продукта

    Finally working