使用HAAR级联和OpenCV识别图像中的对象

时间:2014-05-10 23:12:08

标签: python opencv haar-classifier

(这有点长,但它主要是一个难以理解的解释:)

对于我有一个项目,我需要识别一般形式的对象 -

Object to be recognised

在包含不同形状的更大图像中,如下图所示 - container image

正如你所看到的,我正在寻找的物体是一条红线,每一侧都有十字架(最后一张照片中有5条)。 我有一个大约4,000张图像库,我需要在其中找到对象,其中一些包含这些对象,其中一些不是,就像这张图片一样 - An image without the desired object

经过一些研究,我已经想到了使用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是正确的?我应该使用其他物体识别方法吗?
  • 正面图像尺寸可能是问题的根源吗?如果是这样,我该怎么办呢?

如果我没有包含一些重要数据,请告诉我我会发布。

非常感谢你的帮助, 丹

1 个答案:

答案 0 :(得分:5)

我想,你不会在这里得到haar(或hog)级联分类器的好结果。

  • 你的'针'没有足够的特征/角落(它只有2个十字架和一条线)
  • 级联分类器对旋转非常敏感。看来你的对象可以在这里任意旋转。
  • 如果你训练一个有很多不同旋转的分类器,它就会过度装备。
  • 如果您训练许多分类器(每次旋转一个), - 相同。 ;(

所以,imho,对这种方法没什么希望。

我会去寻找轮廓/ shapeMatching:

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

enter image description here