What I want :

When the user clicks on a button, the program takes the screnshot in the clipboard 'no problem with this part), detects Zone Of Interest (ZOI), cuts the zone and extracts the text of multiple zones for my programme. I try to extract information from a prescription. I know the zones of interests will always be in the same rectangle of color but I'm not sure the prescription will be in fullsize each time I need to extract information. You can see the original image and what I want the ZOI are in red. What the user see

What I want to extract What I tried:

  • First time I tried making the contour of the zone using the color in the font. The program can make a zone around the grey specific zone but the isn't what I want (green box). You can see above the original image, post-process image and the code Result of the code test image in gray
     import numpy as np
            import cv2
    
        # Read input image
        img = cv2.imread('test_image.png')
    
        gray = np.all(img == (227,227,227), 2)
    
        # Convert logical matrix to uint8
        gray = gray.astype(np.uint8)*255
    
        # Find contours
        cnts = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # Use index [-2] to be compatible to OpenCV 3 and 4
    
        # Get contour with maximum area
        c = max(cnts, key=cv2.contourArea)
    
        x, y, w, h = cv2.boundingRect(c)
    
        # Draw green rectangle for testing
        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), thickness = 2)
    
        # Show result
        cv2.imshow('gray', gray)
        cv2.imwrite('niveau_gris.jpg', gray)
        cv2.imshow('img', img)
        cv2.imwrite('test_image_resultat.jpg', img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
  • Second time我试着用两个参数绘制区域轮廓,目的是用文本 Select 区域.该程序根本没有创建区域.您可以看到下面的代码
    import numpy as np
    import cv2
    
    frame = cv2.imread('test_image_constrasate.jpg')
    # Convert BGR to HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # define range of red color in HSV
    lower_red = np.array([189,189,189])
    upper_red = np.array([204,203,204])
    
    mask = cv2.inRange (hsv, lower_red, upper_red)
    contours = cv2.findContours(mask.copy(),
                               cv2.RETR_TREE,
                               cv2.CHAIN_APPROX_SIMPLE)[-2]
    
    if len(contours) > 0:
        red_area = max(contours, key=cv2.contourArea)
        x, y, w, h = cv2.boundingRect(red_area)
        cv2.rectangle(frame,(x, y),(x+w, y+h),(0, 0, 255), 2)
    
    
    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    
    cv2.waitKey(0)
  • Third time我try 使用Hough线变换,但我对处理图像的实验不够,我不确定该过程的重复性,因为屏幕截图可能不是全尺寸的,我不确定如何使用线来制作方框.

provide research

我在StackoverFlow上搜索了以下术语:"OpenCv Select 矩形"、"OpenCv Select 基于 colored颜色 的区域"、"OpenCv如何基于 colored颜色 Select 区域"....

你能帮帮我吗?感谢您今后的帮助

推荐答案

标题方法:

  • 使用matchTemplate找到它左右两侧的按钮
  • 标题是相对于以下内容的矩形

表格的方法:

  • 表标题 colored颜色 为inRange
  • connectedComponentsWithStats
  • 按高度筛选以仅查找表头单元格
  • 查找最宽的单元格
  • 使用条带化背景分隔行

整件事:https://gist.github.com/crackwitz/54a2a8ed3fdb2d07b969ef5aeae9dfcf

实用程序功能:

def crop(im, x, y, w, h):
    (height, width) = im.shape[:2]
    assert w > 0 and h > 0
    assert x >= 0 and y >= 0
    assert (x+w <= width) and (y+h <= height)
    return im[y:y+h, x:x+w]

def find_template(haystack, needle):
    (nw, nh) = needle.shape[:2]
    scores = cv.matchTemplate(haystack, needle, method=cv.TM_SQDIFF)
    (minval, maxval, minloc, maxloc) = cv.minMaxLoc(scores)
    #print(minval, minloc)
    # minval ought to be 0... bug?
    assert minval <= nw*nh*3 * 1**2, "can't find template"
    (x,y) = minloc
    return (x, y, nw, nh)

负载:

im = cv.imread("YebIa.png")#, cv.IMREAD_GRAYSCALE)
(imh, imw) = im.shape[:2]
print("size:", imw, 'x', imh)
imshow(im)

从该特定图片中手动拾取的坐标中提取按钮模板.最好保存这些和imread:

button1 = crop(im, 214, 88, 24, 24)
imshow(button1)
button2 = crop(im, 672, 88, 24, 24)
imshow(button2)

查找按钮,获取标题:

button1_rect = find_template(im, button1)
button2_rect = find_template(im, button2)
b1x, b1y, b1w, b1h = button1_rect
b2x, b2y, b2w, b2h = button2_rect

top = b1y
bottom = b1y + b1h
left = b1x + b1w
right = b2x
title = crop(im, left, top, right-left, bottom-top)
imshow(title)

title

inRange:

# table header, first cell is largest
header_color = (194, 142, 93)
mask = cv.inRange(im, header_color, header_color)

连接的组件:

(nlabels, labels, stats, centroids) = cv.connectedComponentsWithStats(mask)
# print(stats) # x, y, w, h, area (ConnectedComponentsTypes)

筛选和排序组件:

comps = [(label, *stat) for label, stat in enumerate(stats)]
# (label, x, y, w, h, area)
comps = [comp for comp in comps if comp[4] == 25] # height: exactly 25 pixels
comps.sort(key=lambda comp: comp[5], reverse=True) # area, descending... or simply max(key=)
header_comp = comps[0] # largest area
header_rect = header_comp[1:5]
(hx,hy,hw,hh) = header_rect
header = crop(im, *header_rect)
imshow(header)

header

查找表体和行:

# table body
# pixel column just before the header cell (B) contains striped background but no text
# column to the left of that (A) contains only white, until the end
bx = hx
by = hy+hh + 1
bw = hw

columnA = crop(im, bx-2, by, 1, imh-by)[:,0,1]
(I,) = np.where(columnA != 255)
bh = I.min() # table body height

columnB = crop(im, bx-1, by, 1, bh)[:,0,1]
rowmask = (columnB == 255)#.astype(np.int8)
(I,) = np.where(np.diff(rowmask))
I += 1 # diff shifts things back, edge is on the second pixel, not the first

row_tops = np.concatenate(([0], I[:-1]))
row_bottoms = I
# np.vstack([row_tops, row_bottoms]).T

提取每行:

print((bx, by, bw, bh))
for i,(top,bottom) in enumerate(zip(row_tops, row_bottoms)):
    print(f"row {i+1}:")
    imshow(crop(im, bx, by+top, bw, bottom-top))
    print()

rows

Python相关问答推荐

在两极中实施频率编码

sys.modulesgo 哪儿了?

了解shuffle在NP.random.Generator.choice()中的作用

将numpy矩阵映射到字符串矩阵

如何终止带有队列的Python进程?+ 队列大小的错误?

Pandas 除以一列中出现的每个值

如何处理嵌套的SON?

2维数组9x9,不使用numpy.数组(MutableSequence的子类)

TARete错误:类型对象任务没有属性模型'

标题:如何在Python中使用嵌套饼图可视化分层数据?

如何更改分组条形图中条形图的 colored颜色 ?

在np数组上实现无重叠的二维滑动窗口

移动条情节旁边的半小提琴情节在海运

在Python中,从给定范围内的数组中提取索引组列表的更有效方法

如何并行化/加速并行numba代码?

计算天数

如何在Great Table中处理inf和nans

不允许 Select 北极滚动?

递归函数修饰器

使用polars. pivot()旋转一个框架(类似于R中的pivot_longer)