前言:
- 由于项目需要,需要对3D轮廓仪采集的数据进行处理,其中一项重要指标就是测试数据的重复性或精度,那么这个重复性通常是通过视觉处理出来的某个算法标记物的数据来做差衡量的,但是如果这个视觉图形处理算法有问题或者偏差的话,就会导致处理出来的后期数据来衡量重复性是不正确的!
- 所以我们必须从原始数据出发,通过一种对原始数据不大破坏的前提的算法来能在一个明显的量级差异上来反映机台测试数据的重复性。
- 另外,我们采集的是深度图(.tiff类型,16位图,65536种映射),不同的像素值代表不同高度(相对相机的原点的值),那么这些图片的像素值既是原始数据,又承载着真实的被测物的数据对应映射,那么可以用来大作文章最好不过!
- 但是,比较困难的是,以我的样例图片(还算是比较小的)为例,他的width=1451,heigth=8323,换句来说,他有1200多万(1451x8323)像素点,另外,有着不少无用数据(未达视距而渲染出来的像素值,如图上灰色的,且分布不确定),就算割舍下来数据量也很大,又不能做模式特征识别以减少干扰的有用数据,否则,这样处理就没有意义!
- 所以直接处理原始数据,就是直接处理器图片的像素值尤为重要!
一,一些关于其他图像处理的吐槽
- halcon还是比较香的,作为算子和函数封装优良的工具,作为项目的技术框架,往往会节省很多开发时间,但是在这里,读取像素值还是非常缓慢的,相对我后面采用的方法,所以对海量像素值进行处理,并不推荐
- 与上面类似的,C#的内存法或指针法进行同样的处理,更是一言难尽,特别是bitmap类对待16位图不友好,导致读取像素值更慢,又处理不了(所以不予考虑,原先考虑联合halcon开发会比较快)!
- opencv无论是python版还是C++原版可以考虑下,但是没必要,一是他们着重图形处理,二是会花些无用功,考虑它主要可以与numpy库联合使用,较为强大
- 发现没有,虽然有关图形处理我们可能会想到这些,但是我们还是着重点在数据处理上,而且图片本质上是个二维数组(或矩阵),那么numpy库是最好不过的选择!
二,像素比较算法
1.算法原理
- 首先,由于在测试过程中,机台与相机之间不会绝对静止,所以会存在往某个方向上的偏移,因此不能直接对像素值做差比较,要预先处理一波,那么为了消除偏移量的影响,我们对原先的小部分区域做了些均值化处理,并将这些均值添加到新数组averagePixel_list中,具体是这样的:
就这样通过九宫格内像素值归一化处理,有效减少了数据冗余问题,提高运算速度,同时一定程度上消除了未知方向上的偏移影响。- 另外,图片的行高和列宽不会是3的倍数,所以我们遍历终点要与数据最大接近,并且是三的倍数,所以终点可为len(宽或长数组 // 3)* 3,这样会减少数据冗余,且没有大的影响!
- 接着,来到重要的像素值作差了,主要对经过上述处理后的两两图片对应的两个averagePixel_list数组进行对应索引位置像素值做差,并将差值添加到新数组diffpixel_list1中存储,注意:我们这个算法主要针对于同台重复扫三次的(这是算法的硬条件,一般先检查图片的width和height是否达到条件),不同机台就不能直接处理,因为不同机台扫描出来的像素点位置差异非常大,无法通过这种方法处理,但是也能通过这种方法间接看出来!
- 同样按照上一步分别对两两作差得出另一个diffpixel_list2,通过比较对应两个数组索引位置上的差值,若第一个数组的元素值大于第二个数组的元素值,则往第一个数组对应的新数组flagDifference1中增加一个元素,反之,则往第二个数组对应的新数组flagDifference2中增加一个元素,最后通过比较flagDifference那个含有的元素多(或长度长),即一定程度反映出该测试数据的重复性偏差大小(总体量化上来看),因为两个存储差值的数组diffpixel_list,是对应同个机台同个扫描位置的,同时,该数组拥有大概100多万个数据,无法直观去衡量,但是通过这一比较差值大小的数目多少,就可以总体的去量化和把握这些测试数据重复性差异的程度,换句话说:flagDifference元素越多,这代表对应两次扫描出来的差异性会比数目低的两次之间很差异很多!
- 同样,这个误差差异数目量化方法可以对比两个不同机台扫描的重复性!
2.算法原理流程图
3.导出数据
三,编程环境介绍
- 图片对象格式:16位tiff图
- 利用pycharm的python虚拟环境venv
- windows10
- pycharm20.1
- 依赖的库以及对应的版本清单(freeze工具导入导出):
numpy==1.23.3
xlrd==2.0.1
xlutils==2.0.0
xlwt==1.3.0
- 项目文件目录结构如下:
四,编程代码
import os
import numpy as np
import xlwt as xl
from xlrd import open_workbook
from xlutils.copy import copy
import tkinter as tk
import tkinter.filedialog #tk库里的文件选择框模块
# 图片所在文件目录路径
# file1="D:\P-File\python\像素比较\重扫三次\沿X轴扫描-2022_08_30_15_08_27"
# file2="D:\P-File\python\像素比较\重扫三次\沿X轴扫描-2022_08_30_15_24_07"
# file4="D:\P-File\python\像素比较\重扫三次\沿X轴扫描-2022_08_30_15_08_27"
# file3="D:\P-File\python\像素比较\重扫三次\沿X轴扫描-2022_08_30_15_24_07"
class PixelCompare:
# 对原始图片内九个像素点取均值
def averagePixel(self, fileImage):
averagePixel_list = [] # 创建一个空的一维数组
img = np.memmap(fileImage, dtype=np.uint16, shape=(1451, 8323))
img_array = np.array(img, dtype=np.int32)
w_end = (len(img_array) // 3) * 3 #图片宽和高不是3的倍数,要找一个接近的数
h_end = (len(img_array[0]) // 3) * 3
i = img_array
for h in range(0, h_end, 3):
for w in range(0, w_end, 3):
result = i[w][h] + i[w + 1][h] + i[w + 2][h] + \
i[w][h + 1] + i[w + 1][h + 1] + i[w + 2][h + 1] + \
i[w][h + 2] + i[w + 1][h + 2] + i[w + 2][h + 2]
result = result / 9 #对九宫格区域内作均值
averagePixel_list.append(round(result, 3))
return averagePixel_list
# 得到一个文件目录下的所有文件名(包含路径)
def getImagePath(self, filePath):
imgPath_list = []
for i, j, k in os.walk(filePath):
for l in k:
if(l.endswith(".tiff")):
imgPath = filePath + "\\" + l
imgPath_list.append(imgPath)
return imgPath_list
# 对两个数组作差,返回一个新数组
def diffPixel(self, averagePixel_list1, averagePixel_list2):
diffpixel_list = []
if (len(averagePixel_list1) != len(averagePixel_list2)):
print("两数组长度不一致!")
return
else:
for i in range(0, len(averagePixel_list1)):
diff_pixel = averagePixel_list1[i] - averagePixel_list2[i] #作差
diffpixel_list.append(round(diff_pixel, 3))
return diffpixel_list
# 判断两种数据下谁的像素差值大,评分标准为差值大的点flag+=1,然后偶比较flag的数目,flag数目越多重复性越不好,flag数目输出成Excel表
def Comparation(self, diffpixel_list1, diffpixel_list2):
flagDifference1 = []
flagDifference2 = []
flag = 1
if (len(diffpixel_list1) != len(diffpixel_list2)):
print("两种采集作差的数值数组数目不对应")
else:
for i in range(0, len(diffpixel_list1)):
if (diffpixel_list1[i] > diffpixel_list2[i]):
flagDifference1.append(1)
elif(diffpixel_list1[i] < diffpixel_list2[i]):
flagDifference2.append(1)
if (len(flagDifference1) > len(flagDifference2)):
result="第一个采集的数据重复性误差比第二个大"
print(result)
elif (len(flagDifference1) < len(flagDifference2)):
result="第一个采集的数据重复性误差比第二个小"
print(result)
elif (len(flagDifference1) == len(flagDifference2)):
result="两种采集的数据经比较重复性基本一致"
print(result)
return [len(flagDifference1),len(flagDifference2),result]
#创建还不存在的文件夹或覆盖原本的文件夹,xlutils不能打开不存在的文件夹,所以先创建并覆盖先,但如已存在,不用再用xl打开,会报错
def createExcel(self):
wb = xl.Workbook(encoding="utf-8")
sheet = wb.add_sheet("数据比较结果",cell_overwrite_ok = True)
for i in range(0,3) :
sheet.col(i).width=256*40
wb.save(".\\data_excel\\数据比较结果.xls")
def OutData(self,diffpixel_list1, diffpixel_list2,k):
result_list=self.Comparation(diffpixel_list1, diffpixel_list2)
rexcel = open_workbook(".\\data_excel\\数据比较结果.xls",formatting_info=True) # 保留原有样式
# 用 xlutils 提供的copy方法将 xlrd 的对象转化为 xlwt 的对象
excel = copy(rexcel)
# 用 xlwt 对象的方法获得要操作的 sheet
table = excel.get_sheet(0)
title_list=["第一种采集的误差点个数","第二种采集的误差点个数","比较结论"]
for i in range(0,len(title_list)) :
table.write(0, i, title_list[i])
table.write(k+1,i,result_list[i])
excel.save(".\\data_excel\\数据比较结果.xls")
if __name__ == "__main__":
root=tk.Tk()
root.withdraw()
file1=tk.filedialog.askdirectory()
file2 = tk.filedialog.askdirectory()
file3 = tk.filedialog.askdirectory()
file4 = tk.filedialog.askdirectory()
pc = PixelCompare() # 实例化该类
pc.createExcel()
imgPath_list1=pc.getImagePath(file1)
imgPath_list2 = pc.getImagePath(file2)
imgPath_list3= pc.getImagePath(file3)
imgPath_list4= pc.getImagePath(file4)
if(len(imgPath_list1)==len(imgPath_list2) & len(imgPath_list3)==len(imgPath_list4)):
k=0
print("请稍等,正在处理数据中".center(50,"*"))
for i in range(0,len(imgPath_list1)):
averagePixel_list1 = pc.averagePixel(imgPath_list1[i])
averagePixel_list2 = pc.averagePixel(imgPath_list2[i])
averagePixel_list3= pc.averagePixel(imgPath_list3[i])
averagePixel_list4 = pc.averagePixel(imgPath_list4[i])
diffpixel_list1 = pc.diffPixel(averagePixel_list1, averagePixel_list2)
diffpixel_list2 = pc.diffPixel(averagePixel_list3, averagePixel_list4)
wb=pc.OutData(diffpixel_list1, diffpixel_list2,k)
k+=1
print("处理并写入数据完成!".center(50,"-"))
五,一些说明
- 这个算法大概运行完大概需要十几分钟到到二十分钟不等
- 时间复杂度主要集中在遍历循环哪里
- xlwt库与xlutils相辅相成的,左边不能追加写(修改),只能覆盖写(新增),所以使用主次应该是xlwt为主,xlutils为辅
最后文中若有不足,敬请批评指正!算法还处在开发阶段,欢迎集美们集思广益,多提意见!