当前位置: 首页 > 面试题库 >

Remove spurious small islands of noise in an image - Python OpenCV

戚飞雨
2023-03-14
问题内容

我正试图从我的一些图像中去除背景噪音。这就是未过滤图像。

 element = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
 mask = cv2.erode(mask, element, iterations = 1)
 mask = cv2.dilate(mask, element, iterations = 1)
 mask = cv2.erode(mask, element)

当我从原始图像中屏蔽掉不需要的像素时
形象,我得到的是正如你所看到的,中间区域的所有小点都消失了,但是很多
那些来自人口密集地区的人也不见了。为了减少过滤,我
已尝试将“getStructuringElement()”的第二个参数更改为(1,1)
但是这样做给了我第一个图像,好像什么都没有被过滤过。
有什么方法可以在这两个之间加上一些过滤器吗
极端?
另外,有人能给我解释一下
getStructuringElement()do吗?什么是“结构元素”?它有什么作用
它的大小(第二个参数)如何影响过滤级别?


问题答案:

你的很多问题都是因为你不知道该怎么做
形态学图像处理工作,但我们可以消除你的疑虑。你呢
可以把结构元素解释为“基本形态”来比较。1英寸
结构元素对应于要在中查看的像素
此形状和0是您要忽略的形状。有不同的形状,例如
矩形(如你用“变形矩形”算出的),椭圆,圆形,
等。
因此,cv2.getStructuringElement为您返回一个结构元素。
第一个参数指定所需的类型,第二个参数指定所需的类型
指定所需的大小。在你的例子中,你想要一个2 x 2“的矩形。。。
这真的是个正方形,但没关系。
在一个更低级的意义上,您使用结构化元素并从
从左到右,从上到下抓取像素
邻里。每个像素邻域的中心正好位于像素上
你正在看的有趣的东西。每个像素邻域的大小是
与结构元素大小相同。

对于侵蚀,检查像素邻域中
正在触及结构元素。如果每个非零像素都在接触
结构元素像素为1,然后是
与输入相对应的中心位置为1。如果有
至少一个接触的非零像素
1,则输出为0。
对于矩形结构元素,您需要确保
结构元素中的每一个像素都会接触到一个非零像素
像素邻域的图像。如果不是,则输出为0,否则为1。
这有效地消除了噪声的小杂散区域,也降低了噪声
物体的面积。
矩形越大,收缩越大
执行。结构元素的大小是任何对象
比这个矩形结构元素小,你可以考虑
它们被过滤掉而不出现在输出中。基本上,选择一个
1 x 1矩形结构元素与输入图像本身相同
因为这个结构元素适合它里面的所有像素,因为像素是
图像中可能的最小信息表示。

扩张

膨胀与侵蚀相反。如果至少有一个非零像素
结构元素中的像素是1,那么在结构元素中的像素是1
1,否则输出为0。你可以认为这是一个稍微放大的物体
扩大小岛面积。
这里的大小意味着结构元素越大,
物体的面积越大,孤立的物体就越大
岛屿变成了。

你要做的是先腐蚀然后扩张。这就是
被称为打开操作。此操作的目的是移除
小岛的噪音,同时(试图)保持较大的面积
图像中的对象。侵蚀移除了这些岛屿,而膨胀
将较大的对象恢复到其原始大小。
因为某种原因,你又一次被侵蚀了,我不太明白
明白,但没关系。

我个人会做的是先执行关闭操作,这是一个
膨胀之后是腐蚀。关闭有助于对靠近的区域进行分组
一起变成一个物体。因此,你看到有一些更大的
在我们彼此接近之前
别的。因此,我会先做一个结束,然后做一个开始
之后,我们可以消除孤立的噪音区域。注意我要走了
为了使结束结构元素的大小更大,我想确定
我得到附近的像素和开口结构元素的大小所以
我不想错误地移除任何较大的区域。
一旦你这么做了,我会用原件掩盖任何额外的信息
这样你就可以在小岛离开的时候保持较大的区域完好无损
走开。
而不是把腐蚀和膨胀联系起来
由于侵蚀,使用
cv2.morphologyEx,
其中可以指定“MORPH\u OPEN”和“MORPH\u CLOSE”作为标志。
因此,我个人会这样做,假设你的形象是所谓的
斑点.png:

import cv2
import numpy as np

img = cv2.imread('spots.png')
img_bw = 255*(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) > 5).astype('uint8')

se1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
se2 = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
mask = cv2.morphologyEx(img_bw, cv2.MORPH_CLOSE, se1)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, se2)

mask = np.dstack([mask, mask, mask]) / 255
out = img * mask

cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output.png', out)

上面的代码非常简单。首先,我读入图像,然后
我将图像转换为灰度和阈值,强度为5到
创建被视为对象像素的遮罩。这是一个相当干净的房间
所以任何大于5的东西似乎都起作用了。对于形态学
我需要转换图像。
接下来,我们创建两个结构元素-一个是一个5 x 5的矩形
关闭操作和另一个2 x 2的打开操作。我
运行“cv2.morphologyEx”两次以执行打开和关闭操作
分别在阈值图像上。
一旦我这样做了,我堆叠的面具,使它成为一个三维矩阵和除以
所以它变成了一个[0,1]的掩码,然后我们把这个掩码乘以
这样我们就可以抓取图像的原始像素了
以及从掩码输出中保持被认为是真实对象的内容。
剩下的只是举例说明。我在窗口中显示图像,并且
将图像保存到名为输出.png,其目的是向您展示
这张照片是什么样子的。
我明白了:
在此处输入图像描述
记住它并不完美,但它比你拥有它的方式要好得多
以前。你将不得不玩弄结构元素的大小来获得
你认为这是一个很好的输出,但这肯定足以
开始吧。祝你好运!

α+C 版本
已经有一些请求把上面写的代码翻译成C

使用OpenCV的版本。我终于开始写一个C++版本了
代码和它已经在opencv3.1.0上进行了测试。代码如下。
如您所见,代码与Python版本中的代码非常相似。
但是,我用
cv::Mat::setTo
在原始图像的副本上设置任何不是最终图像的部分
屏蔽为0。这与执行元素乘法是一样的
在Python中。

#include <opencv2/opencv.hpp>

using namespace cv;

int main(int argc, char *argv[])
{
    // Read in the image
    Mat img = imread("spots.png", CV_LOAD_IMAGE_COLOR);

    // Convert to black and white
    Mat img_bw;
    cvtColor(img, img_bw, COLOR_BGR2GRAY);
    img_bw = img_bw > 5;

    // Define the structuring elements
    Mat se1 = getStructuringElement(MORPH_RECT, Size(5, 5));
    Mat se2 = getStructuringElement(MORPH_RECT, Size(2, 2));

    // Perform closing then opening
    Mat mask;
    morphologyEx(img_bw, mask, MORPH_CLOSE, se1);
    morphologyEx(mask, mask, MORPH_OPEN, se2);

    // Filter the output
    Mat out = img.clone();
    out.setTo(Scalar(0), mask == 0);

    // Show image and save
    namedWindow("Output", WINDOW_NORMAL);
    imshow("Output", out);
    waitKey(0);
    destroyWindow("Output");
    imwrite("output.png", out);
}

The results should be the same as what you get in the Python version.



 类似资料:

相关阅读

相关文章

相关问答