编程实战(4)——python识别图像中的坐标点并保存坐标数据

编程实战(4)——python识别图像中的坐标点并保存坐标数据

综述

最近因为美赛的需求,需要在提取一些赛道的路线图和地形图中的准确数据,因此对这方面做了一些了解。在研究的过程中,我发现网上的很多相关的帖子并不是很靠谱,不是报错就是没有说清楚一些函数的功能,所以我打算写一篇比较详细的文章。

本文主要讲述利用python接口的opencv来完成图像识别和信息提取并重新绘制、保存为excel数据的详细过程与思路,适合opencv方面的小白观看(需要一定的numpy和matplotlib基础)。如有一些疏漏,请大佬们指出~

代码思路

我会跟着我代码的思路逐一讲解每一步的思路和函数的一些解释;

总体思路如下:

库的安装

这里一共用了三个库

import cv2
import numpy as np
import matplotlib.pyplot as plt

numpy和matplotlib的安装都比较常规,但是cv2的安装不是常规的pip install cv2,是opencv-python,国内镜像下载地址:

pip3 install -i https://mirrors.aliyun.com/pypi/simple/ opencv-python

图片预处理

img = cv2.imread('你的图片路径')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

首先打开图片,然后对图片做一个hsv灰度图的处理,因为我们常规的图片像素点都是rbg空间模式的,我们需要先转化为hsv颜色空间模式(没见过这个图像格式的可以百度一下),以便后面的图像二值化处理;

编程实战(4)——python识别图像中的坐标点并保存坐标数据

上面是我用到的图像,这是东京奥运会公路自行车比赛的路线图,我们要做的就是提取路线像素并坐标化;

图像细化

如果说要处理的图像的线条很粗,那就会影响后面的识别过程,需要先进行图像细化;如果原本图的线条就很细(比如我的),那就可以跳过这一步。

图像细化我是直接参考一个博客的代码的,这里做一个引用:图像细化,骨架提取

写的相当棒,大家可以参考一下。

图像二极化

这里我用到了一个cv库中的inRange函数,这个函数的功能是对读入的图像文件(即函数第一个参数)做一个二值化处理。

总的来说就是我们需要规定两个阈值lowerb和upperb,大于upperb和小于lowerb的图像像素点均会被转化为0(即黑色),在这个范围内的点被转化为255(白色);

low_hsv = np.array([0, 0, 221])
high_hsv = np.array([180, 30, 255])
mask = cv2.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)

我们再来详细的讲一下这两个阈值,如果了解hsv颜色空间的话,很容易可以发现代码的前两行就是hsv颜色空间的两个值,numpy.array函数里面的参数刚好就是色调、饱和度和明度值,因为inRange函数的需要,我们要转化成numpy格式的数组。我这里需要提取所有黑色的坐标,所以设的是黑色与白色的阈值,大家可以根据自己的需求调整颜色阈值。

阈值参考:HSV基本颜色分量范围

这里的mask,就是我们需要提取数据的图像了~

提取数据

为了帮助大家理解,我们先打印看一下mask的具体情况:

print(len(mask))
print(len(mask[0]))
for i in range(len(mask)):
    print(mask[i])

输出:

654
1024
[255 255 255 ... 255 255 255]
[255 255 255 ... 255 255 255]
...
[255 255 255 ... 255 255 255]
[255 255 255 ... 255 255 255]
[255 255 255 ... 255 255 255]

可以看到图像是1024*654的,还有每一行的像素点都是一个numpy数组(numpy数组打印出来元素之间是没有用逗号间隔的),之前24位的hsv图,变成了8位的灰度图(每一项只有一个数据,而不是三个数组成的array);

我们要做的是要知道每一个黑色的像素点的横纵坐标,即在mask这个像素矩阵中,获取值为0的行号和列号

方法也很简单,直接遍历每一个像素,找到值为0的像素点,存取列号和行号即可;

list_y = []
list_x = []

for i in range(len(mask)):
    #print(mask[i])
    xmax = []
    for j in range(len(mask[i])):
        if mask[i][j] == 0:
            #print(mask[i][j],j,i)
            list_x.append(j)
            list_y.append(len(mask)-i)

这里需要注意,很多图像存储数据是从下往上存储的,所以我们在获取列号的时候,需要用图像的高度减去mask的列号,才是真正的列号。

结果展示和保存

matplotlib重绘

检验一下我们获取的图像数据,注意这里需要用散点图模式绘图,不然会有不太好的后果。。。

plt.plot(list_x, list_y, 'o', color='r')
plt.show()

结果如下:

编程实战(4)——python识别图像中的坐标点并保存坐标数据

可以发现提取效果还是不错的~~

写入excel

这一部分的说明直接放到注释里面了

import xlwt

wb = xlwt.Workbook()

ws = wb.add_sheet('sheet1') # 添加一个表

ws.write(0, 0, "x") # 写入数据,3个参数分别为行号,列号,和内容
ws.write(0, 1, "y")

i = 1 #指针,每写一个数据,向下移动写指针一行
for x in list_x:
    ws.write(i, 0, x)
    i += 1

j = 1
for y in list_y:
    ws.write(j, 1, y)
    j += 1

wb.save('1111.xls')

可以看到数据已经保存进excel里面了

编程实战(4)——python识别图像中的坐标点并保存坐标数据

这一次提取其实还有一个小问题,就是相同的横坐标下还是有多个对应该横坐标的点,如果需要做函数分析之类的操作,我们可以直接用excel作按值分组然后去每组的特定值即可,最大值,平均值均可,看个人需求。

全部源码

import cv2
import numpy as np
import matplotlib.pyplot as plt
import xlwt

img = cv2.imread('3.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
low_hsv = np.array([0, 0, 221])
high_hsv = np.array([180, 30, 255])
mask = cv2.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)

print(len(mask))
print(len(mask[0]))

list_y = []
list_x = []

for i in range(len(mask)):
    print(mask[i])
    xmax = []
    for j in range(len(mask[i])):
        if mask[i][j] == 0:
            print(mask[i][j],j,i)
            list_x.append(j)
            list_y.append(len(mask)-i)

plt.plot(list_x, list_y, 'o', color='r')
plt.show()

wb = xlwt.Workbook()

ws = wb.add_sheet('sheet1')

ws.write(0, 0, "x")
ws.write(0, 1, "y")
i = 1
for x in list_x:
    ws.write(i, 0, x)
    i += 1

j = 1
for y in list_y:
    ws.write(j, 1, y)
    j += 1

wb.save('1111.xls')

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年3月10日 上午10:35
下一篇 2023年3月10日 上午10:37

相关推荐