Python 在OpenCV中填充单色背景

Python 在OpenCV中填充单色背景,python,opencv,Python,Opencv,我正在用OpenCV编写一个程序,它拍摄寄生虫卵的照片,并试图识别至少大部分寄生虫卵。我的问题是,我的输入图像有一个大的背景,我有最好的结果。我尝试过填充背景和裁剪背景,但当我这样做的时候,我得到了一个更糟糕的鸡蛋选择 我目前想出的解决方案是使用背景图像,然后填充它。这感觉很简单,因为我只想用黑色填充圆圈之外的任何东西,但我不确定如何实际执行动作。如果有人能指出一种可以使用的方法,或者任何建议,那将是非常好的 以下是图像外观的链接: 谢谢 解决了我的问题,我创建了一个鼠标事件回调,用黑色填充我

我正在用OpenCV编写一个程序,它拍摄寄生虫卵的照片,并试图识别至少大部分寄生虫卵。我的问题是,我的输入图像有一个大的背景,我有最好的结果。我尝试过填充背景和裁剪背景,但当我这样做的时候,我得到了一个更糟糕的鸡蛋选择

我目前想出的解决方案是使用背景图像,然后填充它。这感觉很简单,因为我只想用黑色填充圆圈之外的任何东西,但我不确定如何实际执行动作。如果有人能指出一种可以使用的方法,或者任何建议,那将是非常好的

以下是图像外观的链接:


谢谢

解决了我的问题,我创建了一个鼠标事件回调,用黑色填充我单击的任何内容。下面是我在回调中使用的代码:

def paint(event, x, y, flags, param):
    global opening                                                                                                                         

    if event == cv2.EVENT_LBUTTONDOWN:
        h, w = opening.shape[:2]
        mask = np.zeros((h+2, w+2), np.uint8)
        cv2.floodFill(opening, mask, (x,y), (0, 0, 0)) 
        cv2.imshow("open", opening)

看起来,您需要将图像的外部填充为黑色,因为这样可以更容易地识别鸡蛋,因为它们将以白色隔离

但是如果寄生虫卵神奇地呈现为蓝色呢?我马上解释一下,但是这种方法可以让你摆脱每次需要分析新样本时点击图像的负担

我在C++中写了答案,但是如果你遵循代码的代码,我相信你可以很快地把它翻译成Python。
#include <iostream>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>


int main(int argc, char* argv[])
{
    // Load input image (3-channel)
    cv::Mat input = cv::imread(argv[1]);
    if (input.empty())
    {
        std::cout << "!!! failed imread()" << std::endl;
        return -1;
    }   

    // Convert the input to grayscale (1-channel)
    cv::Mat grayscale = input.clone();
    cv::cvtColor(input, grayscale, cv::COLOR_BGR2GRAY);
窗口上显示的输出为:

此解决方案的优点是,用户不需要与应用程序交互以方便检测鸡蛋,因为鸡蛋已经涂成蓝色

在此之后,可以对输出图像执行其他操作,例如从图像的其余部分执行

因此,为了完整起见,我将再添加几行文本/代码,以演示从这一点开始您可以做些什么,将鸡蛋与图像的其余部分完全隔离开来:

// Isolate blue pixels on the output image
cv::Mat blue_pixels_only;
cv::inRange(output, cv::Scalar(255, 0, 0), cv::Scalar(255, 0, 0), blue_pixels_only);
在此阶段,仅蓝色\u像素\u看起来像什么:

// Get rid of pixels on the edges of the shape 
int erosion_type = cv::MORPH_RECT; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
int erosion_size = 3;
cv::Mat element = cv::getStructuringElement(erosion_type, 
                                            cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
                                            cv::Point(erosion_size, erosion_size));
cv::erode(blue_pixels_only, blue_pixels_only, element);
cv::dilate(blue_pixels_only, blue_pixels_only, element);

cv::imshow("Eggs", blue_pixels_only);
cv::imwrite("blue_pixels_only.png", blue_pixels_only);

在此阶段,仅蓝色\u像素\u看起来像什么:

// Get rid of pixels on the edges of the shape 
int erosion_type = cv::MORPH_RECT; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
int erosion_size = 3;
cv::Mat element = cv::getStructuringElement(erosion_type, 
                                            cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
                                            cv::Point(erosion_size, erosion_size));
cv::erode(blue_pixels_only, blue_pixels_only, element);
cv::dilate(blue_pixels_only, blue_pixels_only, element);

cv::imshow("Eggs", blue_pixels_only);
cv::imwrite("blue_pixels_only.png", blue_pixels_only);

您可以将此作为问题的答案来关闭它。是的,我只需再等一天就可以了。噢,哇,非常感谢,这太棒了!不过,我仍然有一个问题,那就是需要忽略中心的大块,以获得最佳效果(这是用于收集鸡蛋的设备的一部分,因此最好不要选择它)。它是一贯的中心和很大的比较,但并不总是有孔在它的中间。你能推荐一种处理这个问题的方法吗?无需编写代码,只需大致了解如何处理。谢谢我用额外的注释更新了我的答案,我将写另一条注释,告诉你如何在几分钟内去掉中间部分(实际上我是在编写代码时这样做的)。嗯,去除中间部分的技术实际上与我们在这里添加最大圆形时使用的相同。您只需要找出该
区域的值。代码中有一个循环,如果(area>500000&&area<1000000)
执行以下内容,对吗?您需要执行相同的逻辑,但使用不同的硬编码值将中心件绘制为绿色。这将允许您稍后将绿色区域重新绘制为黑色。请随意点击我答案旁边的复选框,选择它作为正式的问题解决方案。
// Get rid of pixels on the edges of the shape 
int erosion_type = cv::MORPH_RECT; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
int erosion_size = 3;
cv::Mat element = cv::getStructuringElement(erosion_type, 
                                            cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
                                            cv::Point(erosion_size, erosion_size));
cv::erode(blue_pixels_only, blue_pixels_only, element);
cv::dilate(blue_pixels_only, blue_pixels_only, element);

cv::imshow("Eggs", blue_pixels_only);
cv::imwrite("blue_pixels_only.png", blue_pixels_only);