从Image .Net中排除小块像素

时间:2018-03-19 12:03:49

标签: c# opencv image-processing aforge

我的黑色图像带有白线。是否可以排除小于特定数字的大块像素?例如:更改从白色到黑色的小于10像素的像素块的颜色。 原始图片: enter image description here

输出图像(白色像素的小区域被移除): enter image description here

现在我使用 AForge 库来处理 C#,,但是 C ++ 解决这个问题的方法也很复杂(例如,Open CV) 。关于如何调用此功能的提示也很受欢迎。

1 个答案:

答案 0 :(得分:2)

不用担心你的细节,看起来似乎很简单

  1. 使用32位的位图并使用LockBits获取扫描线并指示对阵列的指针访问。
  2. 使用2 for循环扫描每个像素
    • 每次找到与目标颜色相匹配的颜色时,向左和向上扫描(X)像素数量,以确定它是否符合您的要求,
    • 如果是,请保留像素,如果不更改的话。
    • 如果你想要更高的速度,你可以将这一切都放在并行工作负载中,也可以用掩码阵列做更多的事情来节省你研究死路径(只是一个想法)
  3. 注意 ,显然你可以把它搞砸了

    <强>〔实施例

    // lock the array for direct access
    var bitmapData = bitmap.LockBits(Bounds, ImageLockMode.ReadWrite, Bitmap.PixelFormat);
    // get the pointer
    var  scan0Ptr = (int*)_bitmapData.Scan0;
    // get the stride
    var  stride = _bitmapData.Stride / BytesPerPixel;
    
    // local method
    void Workload(Rectangle bounds)
    {
       // this is if synchronous, Bounds is just the full image rectangle
       var rect = bounds ?? Bounds; 
       var white = Color.White.ToArgb();
       var black = Color.Black.ToArgb();
    
       // scan all x
       for (var x = rect.Left; x < rect.Right; x++)
       {
          var pX = scan0Ptr + x;
    
          // scan all y
          for (var y = rect.Top; y < rect.Bottom; y++)
          {            
             if (*(pX + y * stride ) != white)
             {
                // this will turn it to monochrome
                // so add your threshold here, ie some more for loops
                //*(pX + y * Stride) = black;
             }
          }
       }
    }
    
    // unlock the bitmap
    bitmap.UnlockBits(_bitmapData);
    

    并行化

    你可以使用这样的东西将图像分成更小的区域

    public static List<Rectangle> GetSubRects(this Rectangle source, int size)
    {
       var rects = new List<Rectangle>();
    
       for (var x = 0; x < size; x++)
       {
          var width = Convert.ToInt32(Math.Floor(source.Width / (double)size));
          var xCal = 0;
    
          if (x == size - 1)
          {
             xCal = source.Width - (width * size);
          }
          for (var y = 0; y < size; y++)
          {
    
             var height = Convert.ToInt32(Math.Floor(source.Height / (double)size));
             var yCal = 0;
    
             if (y == size - 1)
             {
                yCal = source.Height - (height * size) ;
             }
    
             rects.Add(new Rectangle(width * x, height * y, width+ xCal, height + yCal));
          }
       }
    
       return rects;
    }
    

    这个

    private static void DoWorkload(Rectangle bounds, ParallelOptions options, Action<Rectangle?> workload)
    {
       if (options == null)
       {
          workload(null);
       }
       else
       {
          var size = 5 // how many rects to work on, ie 5 x 5
          Parallel.ForEach(bounds.GetSubRects(size), options, rect => workload(rect));
       }
    }
    

    用法

    DoWorkload(Bounds, options, Workload);