如何去除斑块边缘的单个像素?
我有一张二进制图像,如下图所示。请问我该如何去掉这些块边缘的单个像素呢?
如果你不想给出完整的代码,也没关系,你可以解释一些算法或者给我指个方向。
4 个回答
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);
}
4
这看起来像是一个适合用命中与未命中变换来解决的任务。
6
我通过使用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)
给定这张输入图像:
这个脚本会产生以下输出: