Ask Your Question
1

Cascade Classifier HAAR / LBP Advice

asked 2015-07-01 05:56:30 -0600

WillyWonka1964 gravatar image

updated 2015-07-01 07:57:27 -0600

Hi,

I am using OpenCV and python to train HAAR and LBP classifiers to detect white blood cells in video frames. Since the problem is essentially 2D it should be easier than developing other object classifiers and there is great consistency between video frames.

So far I have been using this tutorial: http://coding-robin.de/2013/07/22/tra...

This is an example frame from the video, where I am trying to detect the smaller bright objects: image description

Positive Images: -> nubmer=60 -> filetype=JPG -> width = 50 -> height = 80 image description->image description->image description-> etc

Negative Images: -> number= 600 -> filetype=JPG -> width = 50 -> height = 80 ->image description->image description->image description -> etc

N.B. negative image were extracted as random boxes throughout all frames in the video, I then simply deleted any that I considered contained a cell i.e. a positive image.

Having set-up the images for the problem I proceed to run the classifier following the instructions on coding robin:

find ./positive_images -iname "*.jpg" > positives.txt

find ./negative_images -iname "*.jpg" > negatives.txt

perl bin/createsamples.pl positives.txt negatives.txt samples 1500  "opencv_createsamples -bgcolor 0 -bgthresh 0 -maxxangle 0.1 -maxyangle 0.1 maxzangle 0.1 -maxidev 40 -w 50 -h 80"

find ./samples -name '*.vec' > samples.txt

./mergevec samples.txt samples.vec

opencv_traincascade -data classifier -vec samples.vec -bg negatives.txt\
-numStages 20 -minHitRate 0.999 -maxFalseAlarmRate 0.5 -numPos 60\
-numNeg 600 -w 50 -h 80 -mode ALL -precalcValBufSize 16384\
-precalcIdxBufSize 16384

This throws an error:

Train dataset for temp stage can not be filled. Branch training terminated.

But if I try with different parameters the file 'cascade.xml' is generated, using both HAAR and LBP, changing the minHitRate and maxFalseAlarmRate.

To test the classifier on my image I have a python script

import cv2

imagePath = "./examples/150224_Luc_1_MMImages_1_0001.png"
cascPath = "../classifier/cascade.xml"

leukocyteCascade = cv2.CascadeClassifier(cascPath)
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
leukocytes = leukocyteCascade.detectMultiScale(
    gray,
    scaleFactor=1.2,
    minNeighbors=5,
    minSize=(30, 70),
    maxSize=(60, 90),
    flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)
print "Found {0} leukocytes!".format(len(leukocytes))

# Draw a rectangle around the leukocytes
for (x, y, w, h) in leukocytes:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imwrite('output_frame.png',image)

This is not finding the objects I want, when I have run it with different parameters sometimes it has found 67 objects other times 0, but not the ones that I am trying to detect. Can anyone help me adjust the code to find the objects correctly. Many thanks

edit retag flag offensive close merge delete

Comments

1

I would suggest you to start by removing the noise in your image (where you detect); then try another approach, like threshold (binary image) -> find contours -> fit ellipse -> filter long ellipses (ellipses with high elongation). Doing a cascade classifier combined with another classifier for eliminating the false positives, seems to be too complex for your case (IMHO)

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-07-01 06:25:59 -0600 )edit
2

@thdrksdfthmn you suggested the best and easy solution (IMHO)

sturkmen gravatar imagesturkmen ( 2015-07-01 08:22:49 -0600 )edit

Thanks, the thresholding approach was the first method I tried, but the results were not accurate enough.

WillyWonka1964 gravatar imageWillyWonka1964 ( 2015-07-01 08:59:29 -0600 )edit

i am trying an experimental approach. what is the aimed accuracy

sturkmen gravatar imagesturkmen ( 2015-07-01 09:42:55 -0600 )edit

Aimed at accuracy is 90 to 95%, but the more accurate the better obviously. Actually I have had good results with a classifier, but I am now trying to better optimise the training. I have reduced the size of the positive and negative images from 100 x 100 to 50 x 80, now I cannot get as good a result with Haar features.

WillyWonka1964 gravatar imageWillyWonka1964 ( 2015-07-01 10:00:04 -0600 )edit

What was the accuracy in the threshold manner? And what is now? Have you asked for ideas in the first approach; maybe you can very easily improve it?

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-07-01 10:33:00 -0600 )edit

@WillyWonka1964 i want to share my approach as draft code if you permit.

sturkmen gravatar imagesturkmen ( 2015-07-01 10:37:30 -0600 )edit

Yes, please any help is appreciated

WillyWonka1964 gravatar imageWillyWonka1964 ( 2015-07-01 10:48:15 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2015-07-01 11:15:52 -0600

here an experimental code and result. any comment to get better result is welcome. i believe %90 accuracy is possible this way by some improvements

    #include <opencv2/core/utility.hpp>
    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include <iostream>

    using namespace cv;
    using namespace std;

    Mat src,gray,small,srcclone;
    int threshval = 25;

    static void on_trackbar(int, void*)
    {

        Mat bw = threshval < 128 ? (gray < threshval) : (gray > threshval);
        //imshow( "threshold", bw );

        vector<Vec4i> hierarchy;
        vector<vector<Point> > contours;

        findContours(bw, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
        srcclone=src.clone();
        Rect minRect;

        for (size_t i = 0; i < contours.size(); ++i)
        {
            // Calculate the area of each contour
            double area = contourArea(contours[i]);
            // Ignore contours that are too small or too large
           // if (area < 1e2 || 1e5 < area) continue;

            minRect = boundingRect( Mat(contours[i]) );

            if (minRect.height < 20 ) continue;

            Scalar color= Scalar(0,255,0);

            if (minRect.height < 50 | minRect.height > minRect.width*2) color= Scalar(0,0,255);

            rectangle( srcclone, minRect,color , 2, 8 );

            // Draw each contour only for visualisation purposes
            //  drawContours(srcclone, contours, static_cast<int>(i), Scalar(0, 0, 255), 2, 8, hierarchy, 0);
            // Find the orientation of each shape
        }

        imwrite("result.jpg",srcclone);
        resize(srcclone,small,Size(src.cols/2,src.rows/2));


        imshow( "Connected Components", small );
    }


    int main( int argc, const char** argv )
    {

        src=imread("14357464885366057.png");
        if(src.empty())
        {
            cout << "Could not read input image file: " << endl;
            return -1;
        }


        cvtColor( src, gray, COLOR_BGR2GRAY );


// you can try different values below
        GaussianBlur(gray,gray,Size(5,5),1,1);  
        Mat kernel = Mat::ones(3, 3, CV_8UC1);
        dilate(gray, gray, kernel);


        namedWindow( "Connected Components", 1 );
        createTrackbar( "Threshold", "Connected Components", &threshval, 127, on_trackbar );
        on_trackbar(threshval, 0);

        waitKey(0);
        return 0;
    }

image description

edit flag offensive delete link more

Comments

1

Nice one :) Why not train a small SVM or Naive Bayes classifier on a set of features of the rectangles, like the width, height, area, center of gravity, ... that way the machine learning will learn the optimal thresholds whch are now decided manually.

StevenPuttemans gravatar imageStevenPuttemans ( 2015-07-01 15:05:40 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-07-01 05:56:30 -0600

Seen: 1,932 times

Last updated: Jul 01 '15