I have the following image:
I'm able to grayscale this image with a following OpenCV Java code:
public static Mat grayscale(Mat mat) throws IOException {
Mat gray = new Mat(mat.size(), CvType.CV_8UC1);
if (mat.channels() == 3) {
Imgproc.cvtColor(mat, gray, Imgproc.COLOR_RGB2GRAY);
} else if (mat.channels() == 1) {
mat.copyTo(gray);
} else {
throw new IOException("Invalid image type:" + mat.type());
}
return gray;
}
Right now I need to remove background noise(scanning artifacts, lines) from this image and leave only the scanned card there. I think I have to use threshold, erode there but unable to do it with OpenCV.
I'm playing with it but the result is awful right now and destroys all of the image:
public static Mat clean(Mat srcImage) {
Core.normalize(srcImage, srcImage, 0, 255, Core.NORM_MINMAX);
Imgproc.threshold(srcImage, srcImage, 0, 255, Imgproc.THRESH_OTSU);
//Imgproc.erode(srcImage, srcImage, new Mat());
Imgproc.dilate(srcImage, srcImage, new Mat(), new Point(0, 0), 1);
return srcImage;
}
Please show how it can be achieved with OpenCV Java.
UPDATED
I'm trying to port Python example provided by janu777 to Java. This is my current code:
Mat image = Imgcodecs.imread("test.png");
Mat gray = new Mat();
Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
Core.absdiff(gray, new Scalar(255), gray);
double thresh = Imgproc.threshold(gray, gray, 5, 255, Imgproc.THRESH_TOZERO);
Mat kernel1 = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(11, 11));
Mat kernel2 = Mat.ones(3, 3, CvType.CV_8U);
Mat erosion = new Mat();
Imgproc.erode(gray, erosion, kernel2);
Mat dilation = new Mat();
Imgproc.dilate(erosion, dilation, kernel1);
Right now I have another result than was provide in the answer:
I'm unable to find a place where thresh
parameter should be applied and also I'm not using the iterations parameter for Imgproc.erode
and Imgproc.dilate
methods because the method signature in this case also requires additional Point anchor
parameter which I do not have right now.
What am I doing wrong ?
Following @Silencer comment, I implemented the idea using python and Opencv. Please convert the algorithm to work with java.
Step 1: Morphological Operations using an elliptical structuring element.
img = cv2.imread("test.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.subtract(255,gray)
ret,thresh = cv2.threshold(gray,5,255,cv2.THRESH_TOZERO)
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))
kernel2 = np.ones((3,3),np.uint8)
erosion = cv2.erode(thresh,kernel2,iterations = 1)
dilation = cv2.dilate(erosion,kernel1,iterations = 7)
Step 2: Finding contours
im2,contours, hierarchy = cv2.findContours(dilation,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
c = max(contours, key = cv2.contourArea)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)
Step 3: Rotate image and crop
# rotate img
angle = rect[2]
rows,cols = img.shape[0], img.shape[1]
M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)
img_rot = cv2.warpAffine(img,M,(cols,rows))
# rotate bounding box
rect0 = (rect[0], rect[1], 0.0)
box = cv2.boxPoints(rect)
pts = np.int0(cv2.transform(np.array([box]), M))[0]
pts[pts < 0] = 0
# crop
img_crop = img_rot[pts[1][1]:pts[0][1],
pts[1][0]:pts[2][0]]
cv2.imshow("finalresult.jpg",img_crop)