我正在OpenCV中编写一个程序,它会拍摄寄生虫卵的图片,并试图识别它们中的至少一部分。我的问题是输入图像我有最好的结果,背景很大。我已经尝试过填充背景并将其裁剪掉,但是当我这样做时,我会选择更糟糕的鸡蛋。
我目前经过深思熟虑的解决方案是将图像与背景一起使用,然后将其填入。感觉这很简单,因为我只想用黑色填充该圆圈以外的任何东西,但我不知道如何实际执行该操作。如果有人能指出要使用的方法,或任何可能很棒的建议。
以下是图片外观的链接:
谢谢!
答案 0 :(得分:1)
为我的问题解决了问题,我创建了一个鼠标事件回调函数,它填充了我点击黑色的内容。下面是我在回调中使用的代码:
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)
答案 1 :(得分:1)
您似乎需要将图像的外部填充为黑色,因为它可以更容易识别鸡蛋,因为它们将以白色隔离。
但是,如果寄生虫蛋神奇地显示为蓝色会怎么样?我会在一秒钟内解释这一点,但这种方法可以让您免除每次新样本需要时点击图像的负担待分析。
我用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);
此时灰度的内容如下:
// Locate the black circular shape in the grayscale image
std::vector<std::vector<cv::Point> > contours;
cv::findContours(grayscale, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
// Fill the interior of the largest circular shape found with BLUE
cv::Mat circular_shape = input.clone();
for (size_t i = 0; i < contours.size(); i++)
{
std::vector<cv::Point> cnt = contours[i];
double area = cv::contourArea(cv::Mat(cnt));
if (area > 500000 && area < 1000000) // magic numbers to detect the right circular shape
{
std::cout << "* Area: " << area << std::endl;
cv::drawContours(circular_shape, contours, i, cv::Scalar(255, 0, 0),
cv::FILLED, 8, std::vector<cv::Vec4i>(), 0, cv::Point() );
}
}
此时 circular_shape 的内容如下:
// Create the output image with the same attributes of the original, i.e. dimensions & 3-channel, so we have a colored result at the end
cv::Mat output = cv::Mat::zeros(input.size(), input.type());
// copyTo() uses circular_shape as a mask and copies that exact portion of the input to the output
input.copyTo(output, circular_shape);
cv::namedWindow("Eggs", cv::WINDOW_NORMAL | cv::WINDOW_KEEPRATIO);
cv::imshow("Eggs", output);
cv::resizeWindow("Eggs", 800, 600);
cv::waitKey(0);
return 0;
}
窗口上显示的输出是:
此解决方案的优点是用户无需与应用程序交互以便于检测鸡蛋,因为它们已经涂成蓝色。
此后,可以对输出图像执行其他操作,例如cv::inRange()
到isolate colored objects来自图像的其余部分。
因此,为了完成起见,我将添加更多行文本/代码来演示从这一点开始可以做什么,以便将鸡蛋与图像的其余部分完全隔离: < / p>
// 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);
blue_pixels_only 在此阶段看起来像什么:
// 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);
blue_pixels_only 在此阶段看起来像什么: