首页 > 解决方案 > Python OpenCV 侵蚀和扩张的工作方式与 C# 不同

问题描述

我正在尝试将一些用于生成基准标记的代码从 C# 转换为 Python,但我陷入了侵蚀和扩张。OpenCV 的实现与 C# 实现的工作方式不同。

如果有人想重现该问题,这是完整的 C# 代码:https ://pastecode.io/s/2NbQPPOLCy

以下是标记生成器的 C# 代码的相关部分。它有自己的腐蚀和膨胀功能。

这就是扩张和侵蚀函数的调​​用方式:

//erode, dilate
int rad = 12;
for (int j = 0; j < 5; j++)
{
  dilateBitmap(ref img, 5, rad);
  erodeBitmap(ref img, 5, rad);
}

下面是 C# 的 dilate 和 erode 函数的实现:

public void erodeBitmap(ref Bitmap b, int thres, int radius)
{
    Rectangle rect = new Rectangle(0, 0, fileSize, fileSize);
    BitmapData imgData = b.LockBits(rect, ImageLockMode.WriteOnly, b.PixelFormat);


    Bitmap refImage = (Bitmap)b.Clone();
    BitmapData refData = refImage.LockBits(rect, ImageLockMode.ReadOnly, refImage.PixelFormat);

    List<Point> list = generateBallMask(radius);

    int border = (int)outerCircleTopLeft;

    for (int j = border; j < fileSize - border; j++)
    {
        for (int k = border; k < fileSize - border; k++)
        {
            if (!isWhite(refData, j, k))
            {
                int tot = countNonPixels(refData, j, k, true, list);
              

                if (tot > list.Count / 2)
                {
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4)) = 255;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 1) = 255;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 2) = 255;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 3) = 255;
                }
            }
        }
    }
    refImage.UnlockBits(refData);
    refImage.Dispose();
    b.UnlockBits(imgData);
}

public void dilateBitmap(ref Bitmap b, int thres, int radius)
{
    Rectangle rect = new Rectangle(0, 0, fileSize, fileSize);
    BitmapData imgData = b.LockBits(rect, ImageLockMode.WriteOnly, b.PixelFormat);


    Bitmap refImage = (Bitmap)b.Clone();
    BitmapData refData = refImage.LockBits(rect, ImageLockMode.ReadOnly, refImage.PixelFormat);

    List<Point> list = generateBallMask(radius);

    int border = (int)outerCircleTopLeft;

    for (int j = border; j < fileSize - border; j++)
    {
        for (int k = border; k < fileSize - border; k++)
        {
            if (!isBlack(refData, j, k))
            {
                int tot = countNonPixels(refData, j, k, false, list);

                if (tot > list.Count / 2)
                {
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4)) = 0;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 1) = 0;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 2) = 0;
                    *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 3) = 255;
                }
            }
        }
    }
    refImage.UnlockBits(refData);
    refImage.Dispose();
    b.UnlockBits(imgData);
}

这是在 C# 中生成内核的方式:

 public List<Point> generateBallMask(int r)
        {
            List<Point> maskList = new List<Point>();

            for (int i = -r; i <= r; i++)
            {
                for (int j = -r; j <= r; j++)
                {
                    if ((i == 0) && (j == 0))
                        continue;
                    if (i * i + j * j <= r * r)
                        maskList.Add(new Point(i, j));
                }
            }

                return maskList;
        }

这是 Python 的最小代码:

import numpy as np
import cv2


img = cv2.imread("/home/matjaz/UR/stag/ref/marker generator/HD23/preErodeAndDilate.png", cv2.IMREAD_COLOR)

kernelRadius = 12
kernel = np.zeros((2 * kernelRadius, 2 * kernelRadius), np.uint8) 
for i in range(0, 2 * kernelRadius):
    for j in range(0, 2 * kernelRadius):
        
        if i == kernelRadius and j == kernelRadius:
            continue
        
        if (i - kernelRadius) ** 2 + (j - kernelRadius) ** 2 <= kernelRadius ** 2:
            kernel[i][j] = 255


for _ in range(5):
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)


cv2.imwrite("/home/matjaz/UR/stag/ref/marker generator/HD23/afterErodeAndDilatePython.png", img)

这是在膨胀和腐蚀之前生成的图像。在 C# 和 Python 中的腐蚀和膨胀之前,我设法获得了相同的图像。 预腐蚀和扩张

这是在 C# 中腐蚀和膨胀后的图像: 在此处输入图像描述

这是 Python 中侵蚀和扩张步骤后的图像: 在此处输入图像描述

我想知道如何在 Python 中实现与 C# 侵蚀和扩张后相同的图像

我还尝试将用于膨胀和腐蚀的 C# 代码转换为 python,但没有成功,因为 C# 实现使用指针,这在 Python 中不可用。

我从这个 repo 获得了 C# 代码:https ://github.com/bbenligiray/stag并对其进行了修改,使其全部在一个文件中

标签: pythonc#opencvfiducial-markers

解决方案


推荐阅读