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

Dan*_*Dan 7 python opencv haar-classifier

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

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

要识别的对象

在包含不同形状的更大图像里面,像这样 - 容器图像

正如你所看到的,我正在寻找的对象是一条红线,每边都有十字架(最后一张图片中有5条).我有一个大约4,000张图像库,我需要在其中找到对象,其中一些包含这些对象,而其中一些不像这样的图像 - 没有所需对象的图像

经过一些研究,我认为使用haar级联和openCV是要走的路,所以我写了一个脚本,遍历上面提到的所有4000个图像和提取分离轮廓,就像这个问题中的第一个图像.

然后,我经历了许多轮廓,抓住了大约150个(即150个文件只包含我需要的对象,类似于第一个图像)和大约180个不包含我需要的对象的图像(类似于这里的第三张图片).

然后我开始使用几个教程开始训练过程,但主要是这个.

在这样做时,我遇到了一个问题 - 正如你所看到的,所需的双交叉物体的图像大小不同,甚至没有相同的比例(因为它们可以以任何角度出现 - 水平,对角线等等.).

起初我尝试使用具有不同维度的图像,但这导致了训练过程中的错误,因此,为了解决这个问题,我已将所有正面图像的尺寸更改为350x350(其中一个最大尺度)对象).为了清楚 - 我没有调整图像大小 - 我只是添加了空白区域,使所有图像都是350x350像素.

然后我按照教程中的建议完成了训练过程 - 我创建了样本(宽度 - 24,高度 - 24)并创建了一个级联xml文件,结果证明不是很大(45kb).

现在,我知道150个正面图像和180个负面图像不是很多,但我想在我过滤更多图像并将更多时间投入其中之前至少得到一个概念验证工作.

当cascade.xml文件完成后,我尝试用它来定位一些图像中的一些对象(使用cv2.CascadeClassifier('cascade.xml')cascade.detectMultiScale(img)但是每次尝试都返回零结果.

最后我甚至试图在一个正面图像中找到一个对象(除了一个所需的对象之外什么都没有),但它也返回零结果.

我尝试调整参数,cascade.detectMultiScale(img)目前我正在训练一个36x36样本的级联文件,但我不相信它会起作用.

由于我对这些东西很陌生,我想知道我做错了什么,我想我会在这里问.

进一步来说:

  • 您是否认为在这种情况下使用haar是正确的?我应该使用其他物体识别方法吗?
  • 正面图像尺寸可能是问题的根源吗?如果是这样,我该怎么办呢?

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

Dan,非常感谢你的帮助

ber*_*rak 5

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

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

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

我会选择轮廓/ shape匹配:

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;
}
Run Code Online (Sandbox Code Playgroud)

--------------

> haystack.exe
5 objects found
0 objects found
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述