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
Output image
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.