这里只提取图形/图表是一种使用 OpenCV 的方法:
获取二值图像。加载图像,转换为灰度和Otsu的阈值得到二值图像。
-
连接文本轮廓。我们利用文本按段落结构化的观察结果,因此我们可以用水平轮廓扩张,将单个单词连接成一个轮廓。
删除非图表轮廓。我们使用纵横比和轮廓面积找到轮廓和过滤器。我们通过填充轮廓有效地去除了非图表轮廓。
形成单个边界框。遍历剩余轮廓并确定边界框坐标
提取 ROI。 使用 Numpy 切片裁剪/提取图表。
这是每个步骤的可视化:
阈值图像
使用水平内核扩张
过滤去除非图表轮廓
检测到的图表边界框
提取的投资回报率
注意:这种方法是假设图像中只有一个图表。如果有多个,那么您可以删除第 4 步以获得多个 ROI,并将每个单独的 ROI 保存为单独的图像。我相信这将是一个简单的改变:)
代码
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Dilate with horizontal kernel
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,10))
dilate = cv2.dilate(thresh, kernel, iterations=2)
# Find contours and remove non-diagram contours
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = cv2.contourArea(c)
if w/h > 2 and area > 10000:
cv2.drawContours(dilate, [c], -1, (0,0,0), -1)
# Iterate through diagram contours and form single bounding box
boxes = []
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
boxes.append([x,y, x+w,y+h])
boxes = np.asarray(boxes)
x = np.min(boxes[:,0])
y = np.min(boxes[:,1])
w = np.max(boxes[:,2]) - x
h = np.max(boxes[:,3]) - y
# Extract ROI
cv2.rectangle(image, (x,y), (x + w,y + h), (36,255,12), 3)
ROI = original[y:y+h, x:x+w]
cv2.imshow('image', image)
cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('ROI', ROI)
cv2.waitKey()