Why does calcHist() method create an empty black histogram Mat?

asked 2016-06-26 10:10:45 -0500

Solace gravatar image

updated 2016-06-26 18:46:10 -0500

I have written code to read in an image from gallery, then apply inRange() on it to find blue colored blob and create mask, then used findContours() to find contours, and the drawContours() to draw the contours, then boundingRect() to find a rectangle around the first contour, and then submat() to extract out the submatrix. Then I used Mat.zeroes() to create a mask from that rectangular submat. Then I applied Imgproc.calcHist() to create a histogram, and passed in the Mask as the 3rd argument so that the histogram calculated is that of the area inside the contour only.

Following is a screenshot from my Genymotion emulator, showing the original Mat with green contours around blue detected blobs and then the submatrix I mentioned and then the histogram created by calcHist(), which is black vertical line The question is why is it like this, where is my histogram graph?

image description

Code:

//Get the image from file path
            rgbaMat = new Mat();
            rgbaMatCopy = new Mat();
            rgbaMat = Highgui.imread(filePath);
            rgbaMatCopy = Highgui.imread(filePath);

            //Preprocessing - color space conversion
            Imgproc.cvtColor(rgbaMat, rgbaMat, Imgproc.COLOR_BGR2RGB);
            Imgproc.cvtColor(rgbaMatCopy, rgbaMatCopy, Imgproc.COLOR_BGR2RGB);
            Mat hsvMat = new Mat();
            Imgproc.cvtColor(rgbaMatCopy, hsvMat, Imgproc.COLOR_RGB2HSV);

            //Make the mask from the detected blue colored blob(s)
            Scalar lowerThreshold = new Scalar(100, 146, 148);
            Scalar upperThreshold = new Scalar(134, 255, 255);
            Mat mask = new Mat();
            Core.inRange(hsvMat, lowerThreshold, upperThreshold, mask);

            //Preprocessing
            Mat dilatedMask = new Mat();
            Imgproc.dilate(mask, dilatedMask, new Mat());
            Imgproc.dilate(dilatedMask, dilatedMask, new Mat());

            //Find the contours
            contours = new ArrayList<>();
            Imgproc.findContours(dilatedMask, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

            //Draw the contours
            for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) {
                Imgproc.drawContours(rgbaMatCopy, contours, contourIdx, new Scalar(0, 255, 0), 1);
            }

            //Convert the mat with contours drawn to bitmap and display in imageView
            Bitmap theBitmap = Bitmap.createBitmap(rgbaMatCopy.cols(), rgbaMatCopy.rows(),
                    Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(rgbaMatCopy, theBitmap);
            imageView.setImageBitmap(theBitmap);

            //Find and cut out the smallest bounding rectangle around the first contour from the list of contours
            MatOfPoint firstContour = contours.get(0);
            Rect firstContourBoundingRect = Imgproc.boundingRect(firstContour);
            Mat objectSubmat = new Mat();
            objectSubmat = rgbaMat.submat(firstContourBoundingRect);

            Bitmap objectSubmatBitmap = Bitmap.createBitmap(objectSubmat.cols(), objectSubmat.rows(), Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(objectSubmat, objectSubmatBitmap);
            imageViewOne.setImageBitmap(objectSubmatBitmap);

            //Create mask of the region inside the contour
            Mat regionMask = Mat.zeros(objectSubmat.rows(), objectSubmat.cols(), CvType.CV_8UC1);
            List<MatOfPoint> firstList = new ArrayList<MatOfPoint>();
            firstList.add(firstContour);
            Imgproc.drawContours(regionMask, firstList, 0, new Scalar(255), -1);

            //Preprocessing - color space conversion
            Mat regionHsv = new Mat();
            Imgproc.cvtColor(objectSubmat, regionHsv, Imgproc.COLOR_RGB2HSV);


            //Calculate Histogram
            List<Mat> sourceImageList = new ArrayList<Mat>();
            sourceImageList.add(regionHsv);
            Mat histogram = new Mat();
            //histogramMat.convertTo(histogramMat, CvType.CV_8UC2);
            Imgproc.calcHist(sourceImageList, new MatOfInt(2), regionMask, histogram, new MatOfInt(256), 
                    new MatOfFloat(0f, 256f));


        Highgui.imwrite("/mnt/sdcard/histogram.bmp", histogram);// check
        Mat hish = Highgui.imread("/mnt/sdcard/histogram.bmp");
        Bitmap histogramBitmap = 
                Bitmap.createBitmap(hish.cols(), hish.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(hish, histogramBitmap);
        imageViewTwo.setImageBitmap(histogramBitmap);
edit retag flag offensive close merge delete

Comments

1

take a look at http://docs.opencv.org/3.1.0/d8/dbc/t... you should draw the histogram graph yourself

sturkmen gravatar imagesturkmen ( 2016-06-26 10:40:01 -0500 )edit

@sturkmen I am not able to understand step 5 in their explanation. How do they know that they have to use 512 and 400 as width and height values? Actually all steps after this one is confusing.

Solace gravatar imageSolace ( 2016-06-26 13:47:13 -0500 )edit
1

no spesific values for width and height. you can specify what you wish ( think if you give small values you get a small visualisation graph )

sturkmen gravatar imagesturkmen ( 2016-06-26 14:07:56 -0500 )edit

I am going to do some web search to understand those steps a bit better. If I still don't get it, I will post more specific questions. Thank you so much so far.

Solace gravatar imageSolace ( 2016-06-26 15:39:47 -0500 )edit

@sturkmen Thank you. I tried to write an Android version from the tutorial you pointed me too. But I am getting an here. If you have some time, could you have a look into my new question?

Solace gravatar imageSolace ( 2016-06-26 18:48:31 -0500 )edit
1

could you try the code here

sturkmen gravatar imagesturkmen ( 2016-06-26 18:55:05 -0500 )edit

@sturkmen That code is just like mine here in this question. But looking at the definition of histPrepareImages() - the method in which I have got the error of j < nimages according the the OpenCV Error statement in logcat - given on line 115 of this class tells me that nimages is the second arg, which is numberOfBins in my code. So it means there is something with my numOfBins argument to calcHist(). Can you look into Line 115 of that file and see what might have caused j to be less than numOfBins I passed and any hint on what is going wrong? I don't understand C++ or OpenCV well.

Solace gravatar imageSolace ( 2016-06-26 19:22:35 -0500 )edit

@sturkmen Sorry I was wrong in previous comment. nimages parameter of histPrepareImages() is not what I passed to calcHist() as numberOfBins. Rather, after carefully comparing the parameters of histPrepareImages()here, calcHist()here for C++, and the ones shown in Eclipse (IDE) Javadoc, I learnt that Android API does not have a int nimages argument for calcHist(). For Android API, the calcHist() is Imgproc.calcHist(images, channels, mask, hist, histSize, ranges);

Solace gravatar imageSolace ( 2016-06-26 19:35:31 -0500 )edit