如何删除blob边框上的单个像素?

时间:2014-04-23 08:00:24

标签: python c++ matlab opencv image-processing

我有一个如下所示的二进制图像。如何删除blob边框上的单个像素?

enter image description here

如果您不想提供完整的代码,您可以解释一些算法或指出我正确的方向。

4 个答案:

答案 0 :(得分:4)

我设法通过使用midtiby建议的命中和未命中变换来解决这个问题。我使用以下内核来检测顶部,右侧,底部和左侧单像素。

-1 -1 -1     1 -1 -1      1  1  1     -1 -1  1
-1  1 -1     1  1 -1     -1  1 -1     -1  1  1
 1  1  1     1 -1 -1     -1 -1 -1     -1 -1  1

其中-1代表背景,1代表前景,而0代表不关心(在这种情况下不使用)。

四次点击和未命中变换的结果将用作删除单个像素的掩码。下面是Python / OpenCV中的完整代码:

import numpy as np
import cv2

def hitmiss(src, kernel):
    im = src / 255
    k1 = (kernel == 1).astype('uint8')
    k2 = (kernel == -1).astype('uint8')
    e1 = cv2.erode(im, k1, borderType=cv2.BORDER_CONSTANT)
    e2 = cv2.erode(1-im, k2, borderType=cv2.BORDER_CONSTANT)
    return e1 & e2

if __name__ == "__main__":
    im = cv2.imread('blobs.png', cv2.CV_LOAD_IMAGE_GRAYSCALE)
    _, im_binary = cv2.threshold(im, 50, 255, cv2.THRESH_BINARY)

    kernel = np.array([[-1,-1, 1], 
                       [-1, 1, 1], 
                       [-1,-1, 1]])

    im_mask = np.zeros(im_binary.shape, np.uint8)

    im_mask |= hitmiss(im_binary, kernel)
    im_mask |= hitmiss(im_binary, np.fliplr(kernel))
    im_mask |= hitmiss(im_binary, kernel.T)
    im_mask |= hitmiss(im_binary, np.flipud(kernel.T))

    im_dst = im_binary & ((1 - im_mask) * 255)
    cv2.imwrite('dst.png', im_dst)

鉴于此输入图像:

enter image description here

脚本将生成此输出:

enter image description here

答案 1 :(得分:3)

它看起来像是hit and miss transform的任务。

答案 2 :(得分:0)

您应该对给定的图像执行erosion操作,然后执行dialation操作。不知何故,这些链接上的示例图像是反对的,所以不要混淆。
侵蚀会使用适当的过滤器收缩白色区域。它将删除多余的白色像素。然后你可以进行透视再次扩展白色区域,但没有额外的白色噪声像素。

答案 3 :(得分:0)

我删除此类单个像素的方法是检查每个像素周围的 4个连接的邻居。如果一个像素只有一个邻居,它将被删除。这将擦除"旋转L"的边缘处的一个像素。也不会被删除。

以下是我实现上述方法的代码:

    int neighborNum;
    vector<cv::Point> willRemove;
    for (int i = 1; i < img.rows - 1; i++) {
        for (int j = 1; j < img.cols - 1; j++) {
            neighborNum = 0;
            if (img.at<uchar>(i, j) == 255) {
                // Check 4 connected neighbors
                if (img.at<uchar>(i, j - 1) == 255) {
                    neighborNum++;
                }
                if (img.at<uchar>(i - 1, j) == 255) {
                    neighborNum++;
                }
                if (img.at<uchar>(i, j + 1) == 255) {
                    neighborNum++;
                }
                if (img.at<uchar>(i + 1, j) == 255) {
                    neighborNum++;
                }
                // Found! 
                if (neighborNum == 1) {
                    willRemove.push_back(cv::Point(j, i));
                }
            }
        }
    }
    // Try to remove pixels now    
    for (int i = 0; i < willRemove.size(); i++) {
        cv::circle(img, willRemove[i], 0, cv::Scalar(0, 0, 0), 1, 8, 0);
    }