制作网站备案幕布松阳建设局网站

文章目录
- 1、功能描述
 - 2、代码实现
 - 3、效果展示
 - 4、完整代码
 - 5、参考
 
更多有趣的代码示例,可参考【Programming】
1、功能描述
基于 opencv-python 库,利用形态学的腐蚀和膨胀,提取图片中的水平或者竖直线条
2、代码实现
导入基本的库函数
import numpy as np
import cv2 as cv
 
读入图片(https://raw.githubusercontent.com/opencv/opencv/5.x/doc/tutorials/imgproc/morph_lines_detection/images/src.png),增加读错图片的判断机制
1.jpg

def main(save=False):# Load the imagesrc = cv.imread("./1.jpg", cv.IMREAD_COLOR)# Check if image is loaded fineif src is None:print('Error opening image')return -1
 
可视化图片,并将其转化为灰度图
    # Show source imagecv.imshow("src", src)# [load_image]# [gray]# Transform source image to gray if it is not alreadyif len(src.shape) != 2:gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)else:gray = srcif save:cv.imwrite("gray.jpg", gray)# Show gray imageshow_wait_destroy("gray", gray)# [gray]
 
gray.jpg
 
show_wait_destroy 实现如下 ,关闭图片后才运行后续代码
def show_wait_destroy(winname, img):cv.imshow(winname, img)cv.moveWindow(winname, 500, 0)cv.waitKey(0)cv.destroyWindow(winname)
 
二进制求反灰度图, 并自适应阈值二值化
    # [bin]# Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbolgray = cv.bitwise_not(gray)if save:cv.imwrite("bitwise_not_gray.jpg", gray)bw = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, \cv.THRESH_BINARY, 15, -2)if save:cv.imwrite("adaptiveThreshold.jpg", bw)# Show binary imageshow_wait_destroy("binary", bw)# [bin]
 
bitwise_not_gray.jpg
 
 adaptiveThreshold.jpg

复制图片 adaptiveThreshold.jpg ,准备提取水平线和竖直线
    # [init]# Create the images that will use to extract the horizontal and vertical lineshorizontal = np.copy(bw)vertical = np.copy(bw)# [init]
 
提取水平线
    # [horiz]# Specify size on horizontal axiscols = horizontal.shape[1]  # 1024 colshorizontal_size = cols // 30  # 34# Create structure element for extracting horizontal lines through morphology operationshorizontalStructure = cv.getStructuringElement(cv.MORPH_RECT, (horizontal_size, 1))# Apply morphology operationshorizontal = cv.erode(horizontal, horizontalStructure)if save:cv.imwrite("erode-horizontal.jpg", horizontal)horizontal = cv.dilate(horizontal, horizontalStructure)if save:cv.imwrite("dilate-horizontal.jpg", horizontal)# Show extracted horizontal linesshow_wait_destroy("horizontal", horizontal)# [horiz]
 
首先会构建结构元素 horizontalStructure(定义了形态学操作的邻域形状和大小)
图片列数 // 30 得到全为 1 的数组
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], dtype=uint8)
 
接着腐蚀操作 erode-horizontal.jpg

最后膨胀操作 dilate-horizontal.jpg

至此我们就提取到了图片中的水平方向的线条
接下来我们提取竖直方向的线条
 	# [vert]# Specify size on vertical axisrows = vertical.shape[0]  # 134verticalsize = rows // 30  # 4# Create structure element for extracting vertical lines through morphology operationsverticalStructure = cv.getStructuringElement(cv.MORPH_RECT, (1, verticalsize))# Apply morphology operationsvertical = cv.erode(vertical, verticalStructure)if save:cv.imwrite("erode-vertical.jpg", vertical)vertical = cv.dilate(vertical, verticalStructure)if save:cv.imwrite("dilate-vertical.jpg", vertical)# Show extracted vertical linesshow_wait_destroy("vertical", vertical)# [vert]
 
同理,也是先构建一个结构元素 verticalStructure 
array([[1],[1],[1],[1]], dtype=uint8)
 
腐蚀 erode-vertical.jpg

膨胀 dilate-vertical.jpg

 至此我们提取出了竖直方向的线条
可以拓展一下,
As you can see we are almost there. However, at that point you will notice that the edges of the notes are a bit rough. For that reason we need to refine the edges in order to obtain a smoother result
    '''Extract edges and smooth image according to the logic1. extract edges2. dilate(edges)3. src.copyTo(smooth)4. blur smooth img5. smooth.copyTo(src, edges)'''
 
dilate-vertical.jpg 二进制求反,
    # [smooth]# Inverse vertical imagevertical = cv.bitwise_not(vertical)if save:cv.imwrite("bitwise_not_vertical.jpg", vertical)show_wait_destroy("vertical_bit", vertical)
 
bitwise_not_vertical.jpg
 
 cv2.adaptiveThreshold 适应性阈值二值化
    # Step 1edges = cv.adaptiveThreshold(vertical, 255, cv.ADAPTIVE_THRESH_MEAN_C, \cv.THRESH_BINARY, 3, -2)if save:cv.imwrite("step1_edges.jpg", edges)show_wait_destroy("edges", edges)
 
得到 step1_edges.jpg,实现了边缘检测

看看 cv2.adaptiveThreshold 的介绍仔细分析下实现过程
dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
 

形参 C 从邻域像素的平均值或加权平均值中减去的常数,配置的为负数,附近颜色相近的变黑(eg 纯白区域,像素 255,阈值 255-(-2)=257,都变黑,再 eg,纯黑区域,像素 0,阈值 0-(-2)=2,也是黑),附近颜色变动的变白(黑白交替,白色的部分保留,黑色的部分变黑),可以实现边缘提取,妙
膨胀强化边缘
    # Step 2kernel = np.ones((2, 2), np.uint8)edges = cv.dilate(edges, kernel)if save:cv.imwrite("step2_edges.jpg", edges)show_wait_destroy("dilate", edges)
 
kernel 为
array([[1, 1],[1, 1]], dtype=uint8)
 
step2_edges.jpg

复制 bitwise_not_vertical.jpg
    # Step 3smooth = np.copy(vertical)
 
模糊处理 step4_smooth.jpg
    # Step 4smooth = cv.blur(smooth, (2, 2))if save:cv.imwrite("step4_smooth.jpg", smooth)
 

记录下 step2_edges.jpg 中像素不为零的部分的坐标,也即边缘部分坐标
边缘部分用平滑后的像素替换原来的像素
    # Step 5(rows, cols) = np.where(edges != 0)vertical[rows, cols] = smooth[rows, cols]# Show final resultshow_wait_destroy("smooth - final", vertical)if save:cv.imwrite("smooth_final.jpg", vertical)# [smooth]
 

3、效果展示
输入
 
水平线条

竖直线条

平滑竖直线条后的结果

输入图片

水平线

竖直线

平滑竖直线条后的结果

4、完整代码
"""
@brief Use morphology transformations for extracting horizontal and vertical lines sample code
"""
import numpy as np
import cv2 as cvdef show_wait_destroy(winname, img):cv.imshow(winname, img)cv.moveWindow(winname, 500, 0)cv.waitKey(0)cv.destroyWindow(winname)def main(save=False):# Load the imagesrc = cv.imread("./1.jpg", cv.IMREAD_COLOR)# Check if image is loaded fineif src is None:print('Error opening image')return -1# Show source imagecv.imshow("src", src)# [load_image]# [gray]# Transform source image to gray if it is not alreadyif len(src.shape) != 2:gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)else:gray = srcif save:cv.imwrite("gray.jpg", gray)# Show gray imageshow_wait_destroy("gray", gray)# [gray]# [bin]# Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbolgray = cv.bitwise_not(gray)  # (134, 1024)if save:cv.imwrite("bitwise_not_gray.jpg", gray)bw = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, \cv.THRESH_BINARY, 15, -2)if save:cv.imwrite("adaptiveThreshold.jpg", bw)# Show binary imageshow_wait_destroy("binary", bw)# [bin]# [init]# Create the images that will use to extract the horizontal and vertical lineshorizontal = np.copy(bw)vertical = np.copy(bw)# [init]# [horiz]# Specify size on horizontal axiscols = horizontal.shape[1]  # 1024 colshorizontal_size = cols // 30  # 34# Create structure element for extracting horizontal lines through morphology operationshorizontalStructure = cv.getStructuringElement(cv.MORPH_RECT, (horizontal_size, 1))# Apply morphology operationshorizontal = cv.erode(horizontal, horizontalStructure)if save:cv.imwrite("erode-horizontal.jpg", horizontal)horizontal = cv.dilate(horizontal, horizontalStructure)if save:cv.imwrite("dilate-horizontal.jpg", horizontal)# Show extracted horizontal linesshow_wait_destroy("horizontal", horizontal)# [horiz]# [vert]# Specify size on vertical axisrows = vertical.shape[0]  # 134verticalsize = rows // 30  # 4# Create structure element for extracting vertical lines through morphology operationsverticalStructure = cv.getStructuringElement(cv.MORPH_RECT, (1, verticalsize))# Apply morphology operationsvertical = cv.erode(vertical, verticalStructure)if save:cv.imwrite("erode-vertical.jpg", vertical)vertical = cv.dilate(vertical, verticalStructure)if save:cv.imwrite("dilate-vertical.jpg", vertical)# Show extracted vertical linesshow_wait_destroy("vertical", vertical)# [vert]# [smooth]# Inverse vertical imagevertical = cv.bitwise_not(vertical)if save:cv.imwrite("bitwise_not_vertical.jpg", vertical)show_wait_destroy("vertical_bit", vertical)'''Extract edges and smooth image according to the logic1. extract edges2. dilate(edges)3. src.copyTo(smooth)4. blur smooth img5. smooth.copyTo(src, edges)'''# Step 1edges = cv.adaptiveThreshold(vertical, 255, cv.ADAPTIVE_THRESH_MEAN_C, \cv.THRESH_BINARY, 3, -2)if save:cv.imwrite("step1_edges.jpg", edges)show_wait_destroy("edges", edges)# Step 2kernel = np.ones((2, 2), np.uint8)edges = cv.dilate(edges, kernel)if save:cv.imwrite("step2_edges.jpg", edges)show_wait_destroy("dilate", edges)# Step 3smooth = np.copy(vertical)# Step 4smooth = cv.blur(smooth, (2, 2))if save:cv.imwrite("step4_smooth.jpg", smooth)# Step 5(rows, cols) = np.where(edges != 0)vertical[rows, cols] = smooth[rows, cols]# Show final resultshow_wait_destroy("smooth - final", vertical)if save:cv.imwrite("smooth_final.jpg", vertical)# [smooth]return 0if __name__ == "__main__":main(save=True)
 
5、参考
- Extract horizontal and vertical lines by using morphological operations
 
更多有趣的代码示例,可参考【Programming】
