这里是一些实现传统方法的C99源代码(基于OpenCV doco):
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define MIN_AREA 100.00
#define MAX_TOL 100.00
int main( int argc, char** argv )
{
IplImage* src;
if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0)
{
IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3 );
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvThreshold( src, src, 1, 255, CV_THRESH_BINARY );
cvXorS(src, cvScalar(255, 0, 0, 0), src, NULL);
cvDilate(src, src, NULL, 2);
cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
cvZero( dst );
for( ; contour != 0; contour = contour->h_next )
{
double actual_area = fabs(cvContourArea(contour, CV_WHOLE_SEQ, 0));
if (actual_area < MIN_AREA)
continue;
CvRect rect = ((CvContour *)contour)->rect;
int A = rect.width / 2;
int B = rect.height / 2;
double estimated_area = M_PI * A * B;
double error = fabs(actual_area - estimated_area);
if (error > MAX_TOL)
continue;
printf
(
"center x: %d y: %d A: %d B: %d\n",
rect.x + A,
rect.y + B,
A,
B
);
CvScalar color = CV_RGB( rand() % 255, rand() % 255, rand() % 255 );
cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8, cvPoint(0,0));
}
cvSaveImage("coins.png", dst, 0);
}
}
给定 Carnieri 提供的二进制图像,这是输出结果:
./opencv-contour.out coin-ohtsu.pbm
center x: 291 y: 328 A: 54 B: 42
center x: 286 y: 225 A: 46 B: 32
center x: 471 y: 221 A: 48 B: 33
center x: 140 y: 210 A: 42 B: 28
center x: 419 y: 116 A: 32 B: 19
这是输出图像:
你可以改进的地方:
- 处理不同的椭圆方向(目前,我假设轴是垂直/水平的)。使用图像矩很容易做到这一点。
- 检查对象的凸性(查看
cvConvexityDefects
)
区分硬币和其他物体的最佳方法可能是通过形状。我想不出任何其他低级图像特征(颜色显然不行)。所以,我能想到两种方法:
传统目标检测
您的第一个任务是将对象(硬币和非硬币)与背景分离。如Carnieri建议的Ohtsu方法在这里效果很好。您似乎担心图像是二分图,但我认为这不会成为问题。只要桌面上有足够多的可见区域,您就保证有一个峰值在直方图中。只要桌面上有几个视觉上可区分的物体,您就保证有第二个峰值。
膨胀您的二值图像几次,以消除阈值处理留下的噪声。硬币相对较大,因此它们应该经受得起这种形态学操作。
使用区域生长将白色像素分组为对象--只需迭代地连接相邻的前景像素。在此操作结束时,您将拥有一系列不相交的对象,并且您将知道每个对象占用哪些像素。
从这些信息中,您可以了解到物体的宽度和高度(来自上一步)。因此,现在您可以估计包围物体的椭圆的大小,然后看看这个特定的物体与椭圆匹配程度如何。也许只使用宽度与高度比率更容易。
或者,您可以使用
矩以更精确的方式确定物体的形状。