Change pixel values out of range to a constant in ROI

asked 2015-12-28 02:17:28 -0600

Gradio gravatar image

Hi! I am now building a project based on the sample color blob tracking method. I used bounding rectangles around the contours to indicate the blobs. Now I want to improve this algorithm by using an error correction method. What I do now is simple sum up the pixels in the rect region using elemsum method and calculate the average intensity and set it as the new blob detection parameter in each frame. However, the problem is that this way is not accurate since those pixels outside the contour but inside the bounding rect will be counted as well. And the result is poor.

In order to solve the problem, I would like to loop through each pixel in the rectangle region (which is a submat), and set all pixel values out of range to the desired (or previous) hsv scalar. Then sum up all the pixels again and calculate the average intensity. This would much more accurate and easily solves the problem.

I found some sources online on how to do it in c++ using mat.forEach. I do not want to do the ndk thing and I would like to know if there is a way to do it in Java (Android).

My source code:

public void process(Mat rgbaImage) {
    ...
    Imgproc.findContours(mDilatedMask, contours, mHierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
    ...
    MatOfPoint2f approxCurve = new MatOfPoint2f();

    // Filter contours by area and resize to fit the original image size
    mContours.clear();
    each = contours.iterator();
    while (each.hasNext()) {
        MatOfPoint contour = each.next();
        if (Imgproc.contourArea(contour) > 0.9 * maxArea) {
            Core.multiply(contour, new Scalar(4, 4), contour);
            mContours.add(contour);

            //Todo: Error correction part (Could use the bounding rectangular, maybe with noise removal)
            /*new_hsvColor = Core.sumElems(contour);
            int pointCount =
            for (int i = 0; i < new_hsvColor.val.length; i++)
                new_hsvColor.val[i] /= pointCount;  */

            //Contour processing part
            //Convert contours(i) from MatOfPoint to MatOfPoint2f
            MatOfPoint2f contour2f = new MatOfPoint2f (contour.toArray());

            //Processing on mMOP2f1 which is in type MatOfPoint2f
            double approxDistance = Imgproc.arcLength(contour2f, true)*0.02;
            Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);

            //Convert back to MatOfPoint
            MatOfPoint points = new MatOfPoint( approxCurve.toArray() );

            // Get bounding rect of contour
            Rect rect = Imgproc.boundingRect(points);

            // draw enclosing rectangle (all same color, but you could use variable i to make them unique)
            Imgproc.rectangle(original_frame, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0, 255), 3);

            //Todo: use the bounding rectangular to calculate average intensity (turn the pixels out of the contour to new_hsvColor)
            //Just change the boundary values would be enough
            bounding_rect_rgb = original_frame.submat(rect);
            Imgproc.cvtColor(bounding_rect_rgb, bounding_rect_hsv, Imgproc.COLOR_RGB2HSV_FULL);
            //Todo: change the logic so that pixels outside the contour will be changed to new_hsvColor

            temp = Core.sumElems(bounding_rect_hsv);
            int pointCount = rect.width * rect.height;
            for (int i = 0; i < temp.val.length; i++) {
                temp.val[i] /= pointCount;
                new_hsvColor.val[i] = (new_hsvColor.val[i] + temp.val[i]) / 2;
            }

            // Update the parameters
            double minH = (new_hsvColor.val[0] >= mColorRadius.val[0]) ? new_hsvColor.val[0]-mColorRadius.val[0 ...
(more)
edit retag flag offensive close merge delete