Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does OpenCV recognize the object only in training images?

In order to make my iOS app recognize 1€, 2€ and 0.50€ coins I have been trying to use opencv_createsamples and opencv_traincascade to create my own classifier.xml. So, I cropped 60 images of 2€ coins from a short video like the following:

enter image description here

Then, I combined them with random backgrounds using opencv_createsamples. I obtained 12000 images similar to this:

enter image description here

and I ran the following commands:

opencv_createsamples -img positives/i.jpg -bg negatives.txt -info i.txt -num 210 -maxidev 100 -maxxangle 0.0 -maxyangle 0.0 -maxzangle 0.9 -bgcolor 0 -bgthresh 0 -w 48 -h 48 (for i from 0 to 60)

cat *.txt > positives.txt

opencv_createsamples -info positives.txt -bg negatives.txt -vec 2.vec -num 12600 -w 48 -h 48

opencv_traincascade -data final -vec 2.vec -bg negatives.txt -numPos 12000 -numNeg 3000 -numStages 20 -featureType LBP -precalcValBufSize 2048 -precalcIdxBufSize 2048 -minHitRate 0.999 -maxFalseAlarmRate 0.5 -w 48 -h 48

Training stopped at 13-th stage. Once I got a cascade.xml I tried it at once (with detectMultiScale()) on a simple image taken by my smartphone but nothing is detected:

enter image description here

while if I give as input one of the images used as traning, then it works very good:

enter image description here

I can't really understand why this is happening and it's driving me insane, most of all because I have been trying to make it work for weeks...would you please tell me where I am making the mistake?

The short program I wrote is here:

#include "opencv2/opencv.hpp"

using namespace cv;

int main(int, char**) {

Mat src = imread("2b.jpg");

Mat src_gray;

std::vector<cv::Rect> money;

CascadeClassifier euro2_cascade;

cvtColor(src, src_gray, CV_BGR2GRAY );
equalizeHist(src_gray, src_gray);

if ( !euro2_cascade.load( "cascade.xml" ) ) {
    printf("--(!)Error loading\n");
    return -1;
}

euro2_cascade.detectMultiScale( src_gray, money, 1.1, 3, 0|CASCADE_SCALE_IMAGE/*CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_SCALE_IMAGE*/, cv::Size(10, 10),cv::Size(2000, 2000) );
printf("%d\n", int(money.size()));

for( size_t i = 0; i < money.size(); i++ ) {
    cv::Point center( money[i].x + money[i].width*0.5, money[i].y + money[i].height*0.5 );
    ellipse( src, center, cv::Size( money[i].width*0.5, money[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
}

namedWindow( "Display window", WINDOW_AUTOSIZE );
imwrite("result.jpg",src);
}

I have also tried to take into consideration feature homography for my OpenCV version 3.1. Thus, I downloaded opencv_contrib for my version and tried to compile xfeatures2d module but I get a CMake error in CMakeList file...moreover xfeature2d is not even present inside opencv framework for xcode so even if I made it work on my pc then I could not use it in iOS anyway...

UPDATE

As advised, I've just tried to remove equalizeHist(src_gray, src_gray); and I have set the number of neighbors in detectMultiScale()`` and this is what I get:

enter image description here

UPDATE 2

As someone suggested, following this tutorial I have just created a .vec file using only the cropped positive images, the ones with only the coin. I used this command:

opencv_createsamples -vec i.vec -w 48 -h 48 -num 210 -img ./positives/i.jpg -maxidev 100 -maxxangle 0 -maxyangle 0 -maxzangle 0.9 -bgcolor 0 -bgthresh 0 (for i from 0 to 60)

So as you can see, there's no used background image to create samples. Then, after downloading mergevec.py, I combined all the vectors file together. Now I'm gonna launch another LBP training...I hope it'll work better

like image 576
SagittariusA Avatar asked Feb 03 '16 16:02

SagittariusA


People also ask

How does OpenCV detect object?

OpenCV has a bunch of pre-trained classifiers that can be used to identify objects such as trees, number plates, faces, eyes, etc. We can use any of these classifiers to detect the object as per our need.

How many images do you need to train object detection?

For each label you must have at least 10 images, each with at least one annotation (bounding box and the label). However, for model training purposes it's recommended you use about 1000 annotations per label. In general, the more images per label you have the better your model will perform.

How does Python identify objects in images?

To actually detect objects, you need to call the detectObjectsFromImage() method. Pass the file path of your input image to the “input_image” parameter and the path to the output image (this image will contain the detected object, but it doesn't exist yet), to the “output_image_path” parameter.

Can we train our own deep learning object detection model in OpenCV?

The OpenCV DNN module only supports deep learning inference on images and videos. It does not support fine-tuning and training.


2 Answers

Your cascade was not trained properly. You should not only add different background, but also different scales and different rotations in 3 angles for your coin. Also add more nagatives for training (you have many small detections that mean, that cascade is not trained on negatives)

like image 170
hagor Avatar answered Sep 17 '22 20:09

hagor


This could be the reason due to lack of training data that represent the total scenario of the possible cases. You are not representing full information to the Model. If you don't have more data,

  1. You should rotate images, Crop them at random size and angle, Flipping (Mirroring along vertical edge) basically Data Augmentation
  2. You can do background separation and then use the model for classification
  3. Convert images to grey scale and then operate the classification model (sometime color might mislead the model)
like image 43
Harsh Patel Avatar answered Sep 19 '22 20:09

Harsh Patel