I am trying to convert some code for generating fiducial markers from C# to Python, and I am stuck at erode and dilate. OpenCV's implementation works differently than the C# implementation.
Here is the full C# code if anyone wants to reproduce the problem: https://pastecode.io/s/2NbQPPOLCy
Here are the relevant parts of C# code for the marker generator. It has its own erode and dilate functions.
This is how dilate and erode functions are called:
//erode, dilate
int rad = 12;
for (int j = 0; j < 5; j++)
{
dilateBitmap(ref img, 5, rad);
erodeBitmap(ref img, 5, rad);
}
Here is the implementation of C#'s dilate and erode functions:
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);
}
This is how the kernel is generated in 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;
}
And here is Python's minimal code:
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)
This is the image that is generated before dilation and erosion. I managed to get the same image before erosion and dilation in both C# and Python.
And this is the image after erode and dilate in C#:
This is the image after erode and dilate step in Python:
I would like to know how to achieve in Python the same image as after erode and dilate in C#
I have also tried to convert the C#'s code for dilation and erosion into python, but with without success, because the C# implementation uses pointers, which are not availabel in Python.
I got the C# code from this repo: https://github.com/bbenligiray/stag and modified it so it is all in one file