如何在OpenCV中构建二进制图像的水平投影

时间:2019-01-21 08:20:38

标签: python opencv image-processing image-segmentation

我正在为学校做一个文本分割项目。我需要对二进制图像进行水平图像投影。我想要的结果是这样的:

Example from quora[1]

我正在Python中使用OpenCV。根据问题horizontal and vertical projection of an image和问题Horizontal Histogram in OpenCV的建议,我使用了x_sum = cv2.reduce(img, 0, cv2.REDUCE_SUM, dtype=cv2.CV_32S)来获取总和的数组。

我尝试使用cv2.calcHist来获得水平投影图像,但是我得到的只是一条水平线。我的代码如下:

image = cv2.imread(file_name)
x_sum = cv2.reduce(image, 0, cv2.REDUCE_SUM, dtype=cv2.CV_32S)
horizontal_projection=cv2.calcHist(x_sum,[0],None,[256],[0,256])
cv2.imwrite("image2.png", horizontal_projection) 

请帮助并告诉我我做错了什么。我需要我的水平投影结果像Quora示例一样。

2 个答案:

答案 0 :(得分:1)

在计算投影时,您基本上要对图像每一行的像素求和。但是,您的文本是黑色的,其编码为零,因此您将在连续的文本很多的地方得到小数字,而在连续的文本很少的地方得到大数字-这与您想要的相反-因此您需要反转:

import cv2
import numpy as np

# Load as greyscale
im = cv2.imread('text.png', cv2.IMREAD_GRAYSCALE)

# Invert
im = 255 - im

# Calculate horizontal projection
proj = np.sum(im,1)

数组proj现在的高度为141行,每行对应于图像在该行中的文本数量:

array([    0,     0,     0,     0,    40,    44,   144,   182,   264,
         326,   425,  1193,  2718,  5396,  9272, 11880, 13266, 13597,
       12906, 11962, 10791,  9647,  8554, 20469, 45426, 65714, 81397,
       81675, 66590, 58714, 58046, 60516, 66136, 71794, 77552, 78555,
       74868, 72083, 70139, 70160, 72174, 76409, 82854, 88962, 94721,
       88105, 69126, 47753, 23966, 13845, 17406, 19145, 19079, 16548,
       11524,  8511,  7465,  7042,  7197,  6577,  5022,  3476,  1797,
         809,   450,   309,   348,   351,   250,   232,   271,   279,
         251,   628,  1419,  3259,  6187,  8272,  9551,  9825,  9119,
        7984,  6444,  5305,  4596, 13385, 31647, 46330, 57459, 56139,
       42402, 34928, 33729, 35055, 38874, 41649, 43394, 43265, 41291,
       40126, 39767, 40515, 42390, 44478, 46793, 47881, 47743, 43983,
       36644, 28054, 18242, 15583, 20047, 22038, 21569, 17751, 10571,
        6830,  6580,  6231,  5681,  4595,  2879,  1642,   771,   365,
         320,   282,   105,    88,    76,    76,    28,    28,    28,
          28,     0,     0,     0,     0,     0], dtype=uint64)

我将您的图片裁剪为819x141像素,如下所示:

enter image description here


有很多方法可以进行可视化。这是一个:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load as greyscale
im = cv2.imread('text.png', cv2.IMREAD_GRAYSCALE)

# Invert
im = 255 - im

# Calculate horizontal projection
proj = np.sum(im,1)

# Create output image same height as text, 500 px wide
m = np.max(proj)
w = 500
result = np.zeros((proj.shape[0],500))

# Draw a line for each row
for row in range(im.shape[0]):
   cv2.line(result, (0,row), (int(proj[row]*w/m),row), (255,255,255), 1)

# Save result
cv2.imwrite('result.png', result)

enter image description here

答案 1 :(得分:0)

尝试此简单代码

 import cv2
 import numpy as np
 from matplotlib import pyplot as plt
 img = cv2.imread('text.png', cv2.IMREAD_GRAYSCALE)
 height, width = img.shape[:2]
 med = cv2.medianBlur(img,3)
 cv2.namedWindow("med", cv2.WINDOW_NORMAL)
 cv2.imshow("med",med)
 cv2.waitKey(0)
 sum_x = cv2.reduce(cv2.bitwise_not(med), 1, cv2.REDUCE_SUM, dtype=cv2.CV_32S)
 plt.plot(sum_x)
 plt.xlim([0, height])
 plt.show()