问题描述
我正在从事叶病分类项目。我想使用高效的机器学习分割算法去除整个数据集的模糊背景。输出应该是 ROI 的彩色版本。并且由于数据集的庞大数量,我想要一个训练时间更少的算法。那么,你能给我建议我可以坚持的任何选择吗?
数据集样本附在下面。
leaf image with a disease symptom
解决方法
这个特殊问题并不难解决。它没有想象的那么糟糕,因为只有一个前景对象,这意味着我们可以使用简单的方法解决它。 @Ceopee 的边缘检测本能是正确的,因为这是前景与模糊背景不同的最明显方式。
我对图像进行了灰度处理并使用了 Canny 边缘检测器。我根本没有真正调整它,所以我们得到了一堆边缘,但我们只关心找到叶子的边缘。值得庆幸的是,我们不必为每张图像花费大量时间调整它,因为我们只关心最大的连续边缘。
我扩大图像以连接附近的边缘(canny 给出了 1 像素宽的线,这些线很容易断开),然后使用 findContours 获得所有白线的轮廓。我整理并按区域选择最大的轮廓,然后用它来创建一个蒙版。
遮罩的锯齿状让我感到困扰,所以我先进行了开孔操作(切掉细锯齿),然后进行中间模糊(平滑边缘)。
然后所有要做的就是使用蒙版裁剪图像并完成。 (我不得不将其更改为 jpg 以达到 2mb 的限制,因此此处可能存在一些压缩伪影)。
这是代码(请注意,这是在 OpenCV 3.4 中,如果您使用的是不同的主要版本,则必须修改 findContours 行)
import cv2
import numpy as np
# load image
img = cv2.imread("leaf.jpg");
# grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY);
# canny
canned = cv2.Canny(gray,100);
# dilate to close holes in lines
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(canned,kernel,iterations = 1);
# find contours
# Opencv 3.4,if using a different major version (4.0 or 2.0),remove the first underscore
_,contours,_ = cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE);
# find the biggest contour
biggest_cntr = None;
biggest_area = 0;
for contour in contours:
area = cv2.contourArea(contour);
if area > biggest_area:
biggest_area = area;
biggest_cntr = contour;
# draw contours
crop_mask = np.zeros_like(mask);
cv2.drawContours(crop_mask,[biggest_cntr],-1,(255),-1);
# opening + median blur to smooth jaggies
crop_mask = cv2.erode(crop_mask,iterations = 5);
crop_mask = cv2.dilate(crop_mask,iterations = 5);
crop_mask = cv2.medianBlur(crop_mask,21);
# crop image
crop = np.zeros_like(img);
crop[crop_mask == 255] = img[crop_mask == 255];
# show
cv2.imshow("leaf",img);
cv2.imshow("gray",gray);
cv2.imshow("canny",canned);
cv2.imshow("mask",crop_mask);
cv2.imshow("cropped",crop);
cv2.waitKey(0);
如果您想将其概括为包含多个前景对象,您可以按大小过滤轮廓并拒绝小于某个阈值的轮廓。