0

I'm new at image processing with opencv. I know java and I'm trying to remove background from an image. I've collected some code from internet and tried to fit it together, and results are quite good but I'm missing something.

public class RemoveBackground {
    

    public static void main(String[] args) {
        // Loading the OpenCV core library
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        // Reading the Image from the file and storing it in to a Matrix object
        String file = "C:\\Users\\KobitPC\\Desktop\\Test Pictures/orange.jpg";
        Mat man = Imgcodecs.imread(file);
        man = doCanny(man);

        Imgcodecs.imwrite("C:\\Users\\KobitPC\\Desktop\\Test Pictures/cany.jpg", man);

        System.out.println("Image doCanny");
        
        man = doBackgroundRemoval(man);
        
        Imgcodecs.imwrite("C:\\Users\\KobitPC\\Desktop\\Test Pictures/bgremoved.png", man);

        System.out.println("Image backgroundRemoval");
    }

    private static Mat doCanny(Mat frame) {
        double threshold = 0;
        // init
        Mat grayImage = new Mat();
        Mat detectedEdges = new Mat();

        // convert to grayscale
        Imgproc.cvtColor(frame, grayImage, Imgproc.COLOR_BGR2GRAY);

        // reduce noise with a 3x3 kernel
        Imgproc.blur(grayImage, detectedEdges, new Size(3, 3));

        // canny detector, with ratio of lower:upper threshold of 3:1
       Imgproc.Canny(detectedEdges, detectedEdges, threshold, threshold * 3, 3, false);

        // using Canny's output as a mask, display the result
        Mat dest = new Mat();
        Core.add(dest, Scalar.all(0), dest);
        frame.copyTo(dest, detectedEdges);

        return dest;
    }

    /**
     * Perform the operations needed for removing a uniform background
     *
     * @param frame the current frame
     * @return an image with only foreground objects
     */
    private static Mat doBackgroundRemoval(Mat frame) {

         // init
        Mat hsvImg = new Mat();
        List<Mat> hsvPlanes = new ArrayList<>();
        Mat thresholdImg = new Mat();

        // threshold the image with the histogram average value
        hsvImg.create(frame.size(), CvType.CV_8U);
        Imgproc.cvtColor(frame, hsvImg, Imgproc.COLOR_BGR2HSV);
        Core.split(hsvImg, hsvPlanes);

        double threshValue = getHistAverage(hsvImg, hsvPlanes.get(0));

        
        Imgproc.threshold(hsvPlanes.get(0), thresholdImg, threshValue, 179.0, Imgproc.THRESH_BINARY_INV);
   
       // Imgproc.threshold(hsvPlanes.get(0), thresholdImg, threshValue, 179.0, Imgproc.THRESH_BINARY);

        Imgproc.blur(thresholdImg, thresholdImg, new Size(5, 5));

        // dilate to fill gaps, erode to smooth edges
        Imgproc.dilate(thresholdImg, thresholdImg, new Mat(), new Point(-1, 1), 6);
        Imgproc.erode(thresholdImg, thresholdImg, new Mat(), new Point(-1, 1), 6);

        Imgproc.threshold(thresholdImg, thresholdImg, threshValue, 179.0, Imgproc.THRESH_BINARY);

        // create the new image
        Mat foreground = new Mat(frame.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
        frame.copyTo(foreground, thresholdImg);

        return foreground;
    }
    /**
     * Get the average value of the histogram representing the image Hue
     * component
     *
     * @param hsvImg
     *            the current frame in HSV
     * @param hueValues
     *            the Hue component of the current frame
     * @return the average value
     */
    private static double getHistAverage(Mat hsvImg, Mat hueValues) {
            // init
            double average = 0.0;
            Mat hist_hue = new Mat();
            MatOfInt histSize = new MatOfInt(180);
            List<Mat> hue = new ArrayList<>();
            hue.add(hueValues);

            // compute the histogram
            Imgproc.calcHist(hue, new MatOfInt(0), new Mat(), hist_hue, histSize, new MatOfFloat(0, 179));

            // get the average for each bin
            for (int h = 0; h < 180; h++)
            {
                    average += (hist_hue.get(h, 0)[0] * h);
            }

            return average = average / hsvImg.size().height / hsvImg.size().width;
    }
} 

Input Image

Input image

Output image

Output image after background removal

The t-shirt shape is cropped very well, but I don't understand why t-shirt contains those lines. I know there is a way to remove them and get a clean image without background.

Community
  • 1
  • 1
gate
  • 3
  • 4
  • Well, the tshirt has those lines because you basically did an edge detection on the image, then you pass this output to background-removal function...is this intended?If yes, the result is correct – Mauro Dorni Oct 29 '19 at 15:06
  • Thanks for the reply, which part of code should I edit to remove those lines because I don't want them, I need the clean tshirt. – gate Oct 29 '19 at 15:13
  • Try just to comment this line : 'man = doCanny(man);' – Mauro Dorni Oct 30 '19 at 08:38
  • I did, here is the output https://imgur.com/Hn7vY1N – gate Oct 30 '19 at 09:25
  • Ok, so edges are actually used (sorry I didn't test your code), then you must restore that line of code. I dont know where you took this code, so I tell you how I would proceed: from the output image, find the biggest contour (like done here https://stackoverflow.com/questions/46187563/finding-largest-contours-c), draw it filled, and use this new image as mask on your original image – Mauro Dorni Oct 30 '19 at 09:36

0 Answers0