OpenCV 去除背景噪声和伪影
OpenCV remove background noise and artifacts
我有以下图片:
我可以使用以下 OpenCV Java 代码对这张图片进行灰度化:
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;
}
现在我需要从这张图片中去除背景噪音(扫描伪影、线条),只留下扫描的卡片。我想我必须使用阈值,在那里进行侵蚀但无法使用 OpenCV 来完成。
我正在玩它,但现在的结果很糟糕,破坏了所有图像:
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;
}
请说明如何使用 OpenCV 实现它 Java。
已更新
我正在尝试将 janu777 提供的 Python 示例移植到 Java。这是我当前的代码:
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);
现在我得到了答案中提供的另一个结果:
我找不到应该应用 thresh
参数的地方,而且我也没有为 Imgproc.erode
和 Imgproc.dilate
方法使用迭代参数,因为方法签名在这种情况下还需要我现在没有的额外 Point anchor
参数。
我做错了什么?
在@Silencer 评论之后,我使用 python 和 Opencv 实现了这个想法。请转换算法以使用 java.
步骤 1: 使用椭圆结构元素的形态学运算。
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)
结果:
步骤 2: 寻找等高线
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)
结果:
步骤 3: 旋转图像并裁剪
# 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)
我有以下图片:
我可以使用以下 OpenCV Java 代码对这张图片进行灰度化:
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;
}
现在我需要从这张图片中去除背景噪音(扫描伪影、线条),只留下扫描的卡片。我想我必须使用阈值,在那里进行侵蚀但无法使用 OpenCV 来完成。
我正在玩它,但现在的结果很糟糕,破坏了所有图像:
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;
}
请说明如何使用 OpenCV 实现它 Java。
已更新
我正在尝试将 janu777 提供的 Python 示例移植到 Java。这是我当前的代码:
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);
现在我得到了答案中提供的另一个结果:
我找不到应该应用 thresh
参数的地方,而且我也没有为 Imgproc.erode
和 Imgproc.dilate
方法使用迭代参数,因为方法签名在这种情况下还需要我现在没有的额外 Point anchor
参数。
我做错了什么?
在@Silencer 评论之后,我使用 python 和 Opencv 实现了这个想法。请转换算法以使用 java.
步骤 1: 使用椭圆结构元素的形态学运算。
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)
结果:
步骤 2: 寻找等高线
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)
结果:
步骤 3: 旋转图像并裁剪
# 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)