use*_*904 5 python opencv image-processing omr
我正在研究 opencv 问题来找出哪些圆圈被填充。然而,有时圆圈的边缘是误报的原因。我想知道是否可以通过将 RGB 中具有高 R 值的所有像素变成白色来删除这些圆圈。我的方法是创建一个粉红色的像素蒙版,然后从原始图像中减去蒙版以删除圆圈。截至目前,我正在戴黑色面具。我做错事了。请指导。
rgb = cv2.imread(img, cv2.CV_LOAD_IMAGE_COLOR)
rgb_filtered = cv2.inRange(rgb, (200, 0, 90), (255, 110, 255))
cv2.imwrite('mask.png',rgb_filtered)
Run Code Online (Sandbox Code Playgroud)

这是我的解决方案。不幸的是它也是用 C++ 编写的,它的工作原理如下:
检查每个圆圈内部是否有更多的前景(绘图)或背景(白皮书)像素(按某个比例阈值)。
int main()
{
cv::Mat colorImage = cv::imread("countFilledCircles.png");
cv::Mat image = cv::imread("countFilledCircles.png", CV_LOAD_IMAGE_GRAYSCALE);
// threshold the image!
cv::Mat thresholded;
cv::threshold(image,thresholded,0,255,CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
// save threshold image for demonstration:
cv::imwrite("countFilledCircles_threshold.png", thresholded);
// find outer-contours in the image these should be the circles!
cv::Mat conts = thresholded.clone();
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(conts,contours,hierarchy, CV_RETR_EXTERNAL, CV_C HAIN_APPROX_SIMPLE, cv::Point(0,0));
// colors in which marked/unmarked circle outlines will be drawn:
cv::Scalar colorMarked(0,255,0);
cv::Scalar colorUnMarked(0,0,255);
// each outer contour is assumed to be a circle
// TODO: you could first find the mean radius of all assumed circles and try to find outlier (dirt etc in the image)
for(unsigned int i=0; i<contours.size(); ++i)
{
cv::Point2f center;
float radius;
// find minimum circle enclosing the contour
cv::minEnclosingCircle(contours[i],center,radius);
bool marked = false;
cv::Rect circleROI(center.x-radius, center.y-radius, center.x+radius, center.y+radius);
//circleROI = circleROI & cv::Rect(0,0,image.cols, image.rows);
// count pixel inside the circle
float sumCirclePixel = 0;
float sumCirclePixelMarked = 0;
for(int j=circleROI.y; j<circleROI.y+circleROI.height; ++j)
for(int i=circleROI.x; i<circleROI.x+circleROI.width; ++i)
{
cv::Point2f current(i,j);
// test if pixel really inside the circle:
if(cv::norm(current-center) < radius)
{
// count total number of pixel in the circle
sumCirclePixel = sumCirclePixel+1.0f;
// and count all pixel in the circle which hold the segmentation threshold
if(thresholded.at<unsigned char>(j,i))
sumCirclePixelMarked = sumCirclePixelMarked + 1.0f;
}
}
const float ratioThreshold = 0.5f;
if(sumCirclePixel)
if(sumCirclePixelMarked/sumCirclePixel > ratioThreshold) marked = true;
// draw the circle for demonstration
if(marked)
cv::circle(colorImage,center,radius,colorMarked,1);
else
cv::circle(colorImage,center,radius,colorUnMarked,1);
}
cv::imshow("thres", thresholded);
cv::imshow("colorImage", colorImage);
cv::imwrite("countFilledCircles_output.png", colorImage);
cv::waitKey(-1);
}
Run Code Online (Sandbox Code Playgroud)给我这些结果:
大津阈值处理后:

最终图像:

我是这样做的:
这是我的示例结果:

当我们在原始图像上绘制结果时:

这是示例代码(抱歉,使用 C++):
void findFilledCircles( Mat& img ){
Mat gray;
cvtColor( img, gray, CV_BGR2GRAY );
/* Apply some blurring to remove some noises */
GaussianBlur( gray, gray, Size(5, 5), 1, 1);
/* Otsu thresholding maximizes inter class variance, pretty good in separating background from foreground */
threshold( gray, gray, 0.0, 255.0, CV_THRESH_OTSU );
erode( gray, gray, Mat(), Point(-1, -1), 1 );
/* Sadly, this is tuning heavy, adjust the params for Hough Circles */
double dp = 1.0;
double min_dist = 15.0;
double param1 = 40.0;
double param2 = 10.0;
int min_radius = 15;
int max_radius = 22;
/* Use hough circles to find the circles, maybe we could use watershed for segmentation instead(?) */
vector<Vec3f> found_circles;
HoughCircles( gray, found_circles, CV_HOUGH_GRADIENT, dp, min_dist, param1, param2, min_radius, max_radius );
/* This is just to draw coloured circles on the 'originally' gray image */
vector<Mat> out = { gray, gray, gray };
Mat output;
merge( out, output );
float diameter = max_radius * 2;
float area = diameter * diameter;
Mat roi( max_radius, max_radius, CV_8UC3, Scalar(255, 255, 255) );
for( Vec3f circ: found_circles ) {
/* Basically we extract the region of the circles, and count the ratio of black pixels (0) and white pixels (255) */
Mat( gray, Rect( circ[0] - max_radius, circ[1] - max_radius, diameter, diameter ) ).copyTo( roi );
float filled_percentage = 1.0 - 1.0 * countNonZero( roi ) / area;
/* If more than half is filled, then maybe it's filled */
if( filled_percentage > 0.5 )
circle( output, Point2f( circ[0], circ[1] ), max_radius, Scalar( 0, 0, 255), 3 );
else
circle( output, Point2f( circ[0], circ[1] ), max_radius, Scalar( 255, 255, 0), 3 );
}
namedWindow("");
moveWindow("", 0, 0);
imshow("", output );
waitKey();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7369 次 |
| 最近记录: |