(这有点长,但基本上是一个不难理解的解释:)
对于我的项目,我需要识别一般形式的对象,如下所示 -
在包含不同形状的更大图像中,例如这个 -
如您所见,我正在寻找的对象是一条红线,每边都有十字(最后一张图片中有 5 个十字)。 我有大约 4,000 张图片,我需要在其中找到对象,其中一些包含这些对象,而另一些则不包含这些对象,例如这张图片 -
在做了一些研究之后,我发现使用 haar 级联和 openCV 是可行的方法,所以我编写了一个脚本来遍历上述所有 4,000 张图像并提取单独的轮廓,就像这个问题中的第一张图像一样。
然后,我遍历了许多轮廓,抓取了大约 150 个轮廓(即 150 个只包含我需要的对象的文件,类似于第一张图像)和大约 180 个不包含我需要的对象的图像(类似于这里的第三张图片)。
然后我开始了训练过程,使用了几个教程,但主要是this one .
在这样做的时候,我遇到了一个问题——正如你所看到的,所需的双叉对象的图像大小不一样,甚至不具有相同的比例(因为它们可以以任何角度出现 -水平、对角线等)。
起初我尝试使用不同尺寸的图像,但这导致了训练过程中的错误,因此,为了解决这个问题,我将所有正图像的尺寸更改为 350x350(最大尺寸)对象之一)。明确一点 - 我没有调整图像的大小 - 我只是在周围添加了空白,使所有图像都为 350x350 像素。
然后我按照教程中的建议完成了训练过程 - 我创建了样本(宽度 - 24,高度 - 24)并创建了一个级联 xml 文件,结果证明它不是很大(45kb)。
现在,我知道 150 张正面图像和 180 张负面图像并不算多,但我想在过滤更多图像并投入更多时间之前至少进行概念验证。
当 cascade.xml 文件完成后,我尝试使用它来定位某些图像中的某些对象(使用 cv2.CascadeClassifier('cascade.xml')
和 cascade.detectMultiScale (img)
但每次尝试都返回零结果。
最后,我什至尝试在其中一个正图像中定位一个对象(其中只包含一个所需的对象),但它也返回零结果。
我尝试调整 cascade.detectMultiScale(img)
的参数,目前我正在使用 36x36 样本训练级联文件,但我不确定它是否有效。
由于我对这些东西很陌生,我想知道我做错了什么,我想我会在这里问。
更具体地说:
- 您认为在这种情况下使用 haar 是否正确?我应该使用其他对象识别方法吗?
- 正图像尺寸是否是问题的根源?如果是这样,我该怎么做?
如果我没有包含一些重要数据,请告诉我,我会发布它。
非常感谢您的帮助, 丹
最佳答案
我猜,你不会从这里的 haar(或 hog)级联分类器中得到好的结果。
- 您的“针”没有足够的特征/角(只有 2 个十字和一条线)
- 级联分类器对旋转非常敏感。看起来你的对象可以在这里进行任意旋转。
- 如果您使用许多不同的旋转训练分类器,它就会过度拟合。
- 如果您训练许多 分类器(每次轮换一个),- 相同。 ;(
所以,恕我直言,这种方法的希望不大。
我会选择轮廓/形状匹配:
void findNeedles( const std::vector<cv::Point> & needle_contour, const cv::Mat & haystack_binarized)
{
int nfound = 0;
std::vector<std::vector<cv::Point>> contours;
cv::findContours(haystack_binarized, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
for (size_t i = 0; i < contours.size(); i++)
{
// pre-filter for size:
if ( ( contours[i].size() < needle_contour.size()/2 )
|| ( contours[i].size() > needle_contour.size()*2 ) )
continue;
double d = cv::matchShapes(contours[i],needle_contour,CV_CONTOURS_MATCH_I2,0);
if ( d < 8.4 ) // heuristic value, experiments needed !!
{
cv::drawContours(haystack_binarized, contours, i, 128, 3);
nfound ++;
}
}
cerr << nfound << " objects found" << endl;
cv::imshow("haystack",haystack_binarized);
//imwrite("hay.png",haystack_binarized);
cv::waitKey();
}
int main()
{
// 1. get the contour of our needle:
Mat needle = imread("needle.png",0);
Mat needle_b;
threshold(needle,needle_b,120,255,1);
imshow("needle",needle_b);
std::vector<std::vector<cv::Point>> needle_conts;
cv::findContours(needle_b, needle_conts, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if ( needle_conts.size() == 0 )
{
std::cout << " no contour Found" << std::endl;
return -1;
}
std::vector<cv::Point> needle_contour = needle_conts[0];
// 2. check a positive sample:
Mat haypos = imread("hay_pos.png",0);
Mat haypos_b;
threshold(haypos,haypos_b,120,255,1);
findNeedles(needle_contour, haypos_b);
// 3. check a negative sample:
Mat hayneg = imread("hay_neg.png",0);
Mat hayneg_b;
threshold(hayneg,hayneg_b,120,255,1);
findNeedles(needle_contour, hayneg_b);
return 0;
}
----------------
> haystack.exe
5 objects found
0 objects found
关于python - 使用 HAAR 级联和 OpenCV 识别图像中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23587296/