将一组点变成单个像素

Turn group of points into single pixel

我有一张包含 4 组点的黑白图像,我需要将每组转换为一个点。

我的想法是按距离找到移除点,所以如果一个像素可能与另一个相距 20px,我会转而移除一个并保留另一个,并重复该过程直到我只得到 4 个像素,但是它似乎不太适合性能。

我有更好的方法吗?

谢谢

图片:

您的想法离可行的解决方案不远。您可以设计一个简单的算法,其工作原理如下:

  • 按光栅顺序扫描图像,直到遇到白色像素,

  • 从这个像素开始,通过种子填充擦除整个连通分量,

  • 恢复初始像素并继续扫描到图像末尾。

擦除,

  • 将当前像素设置为黑色,

  • 对所有白色邻居进行递归(您可以考虑具有共同边缘的四个像素以及可选的四个接触角的像素)。

请注意,如果连接的组件组件很大,可能会发生堆栈溢出。还要注意图像的边缘像素(一些邻居缺失)。

这个算法非常有效,因为它只会访问黑色像素一次,而白色像素只会访问两次(白色时一次,擦除后第二次)。

这是一个可能的解决方案。基本上,我会检测原始图像上的四个斑点,获取它们的 边界框 并计算它们的 质心 。我用黑色的质心在这个位置flood-fill,然后在相同的位置画一个像素。

但是,您的图像是巨大且压缩的。我调整了它的大小(如果你不想调整它的大小,你可以将 scalePercent 保持在 100),将它转换为 grayscale 然后 threshold 它 - 正如我说,你的图像被压缩了,有些像素不是真正的白色,所以阈值给了我一个真正的二值图像:

# imports:
import cv2

# Set image path
imagePath = "C://opencvImages//"
imageName = "juPHJ.jpg"

# Read image:
inputImage = cv2.imread(imagePath + imageName)

# Resize percent:
scalePercent = 20

# Calculate new dimensions:
newWidth = int(inputImage.shape[1] * scalePercent / 100)
newHeight = int(inputImage.shape[0] * scalePercent / 100)

# Resize image
inputImage = cv2.resize(inputImage, (newWidth, newHeight))

# Input deep copy
inputCopy = inputImage.copy()

# Convert BGR to grayscale:
grayInput = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)

# Get binary image via Otsu:
_, binaryImage = cv2.threshold(grayInput, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

现在,让我们提取白色斑点,获取它们的边界框,计算质心并相应地flood-fill

# Extract blobs:
contours, _ = cv2.findContours(binaryImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Loop through the blobs, get their bounding boxes:
for i, c in enumerate(contours):

    # Get blob bounding box:
    x, y, w, h = cv2.boundingRect(c)
    # Compute centroid:
    cx = int(x + 0.5 * w)
    cy = int(y + 0.5 * h)

    # Flood-fill at the center:
    fillPosition = (cx, cy)
    fillColor = (0, 0, 0)
    cv2.floodFill(binaryImage, None, fillPosition, fillColor, loDiff=(10, 10, 10), upDiff=(10, 10, 10))

    # Draw a pixel at the center:
    binaryImage[cy, cx] = 255

    # Show new Image:
    cv2.imshow("New Image", binaryImage)
    cv2.waitKey(0)

这是输出(不过你必须真正放大才能看到单个像素):