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:
Then, I combined them with random backgrounds using opencv_createsamples
. I obtained 12000 images similar to this:
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:
while if I give as input one of the images used as traning, then it works very good:
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:
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
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.
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.
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.
The OpenCV DNN module only supports deep learning inference on images and videos. It does not support fine-tuning and training.
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)
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,
grey scale
and then operate the classification model (sometime color might mislead the model)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With