python摸鱼笔记
2023-12-21 2.2k 字  

想当初曾经许下豪情壮志,想要一年学会数据分析,玩转爬虫……而如今,还在艰难起步爬坡阶段……

能更新这个废弃已久的笔记本,说明我真的很无聊

图像处理

学习图像处理的过程就是无数个摸鱼的时段叠加

更新至2023/12/20

废话章节

“python作为目前最好上手且最热门的语言,不学习一下实在血亏,万一毕业找不到工作还可以转行当数据分析师。”这样的想法在我给我导搬砖的时候就萌生了,不过我一向拖延,加上mathematica和orign处理大部分数据绰绰有余,于是我就继续耽搁着了。

疫情被困在家无聊到发疯,我不可思议地产生了学习的冲动。在看完B站各种python入门视频且跟着视频学习了一段时间,并成功地在一个月没碰电脑,忘光知识点之后,我悟了:

若不根据自己需求来写程序,并从中查找各种函数的用途,直接刷课程这种学习模式压根不适合我。

意识到这点的我欣然地接受了自己的半途而废,毫无愧疚感地将自己的热情投入到其他爱好上去了。

辗转到进入社畜阶段,再继续接触Python则是因为我用Origin用腻了(怎么有种嫌弃糟糠之妻的既视感),而且后续工作内容使用zemax和rsoft比较多,zemax的内置看光斑模式又太死板了,需要点开多个窗口,还得用鼠标读取点的位置再返回(2016版本以上自带了光斑尺寸计算,但我感觉和我需要的那个能量定义有点差异)。如果能直接读取zemax里面的光斑像素点,酷炫地3d建模,拟合曲线并返回参数。那我就不用每次手动把zemax里探测器的数据复制粘贴到excel里再画图了。

除了处理光斑,如果python能帮我一键给所有物体镀膜就好了(这个还在琢磨中),每次一个一个点开再向下拉取选择镀膜系数真的费眼睛。

我看了下这两软件都支持python和matlab的接口,matlab快是快,但占用内存太大了,就想转成python试试。

案例分析

参考案例是:《python处理高斯光束的分布图像》

python处理高斯光束的分布图像_如何判断图形为高斯-CSDN博客

博主的代码过程很详细,除了一些不常用的数据包,结尾附上了成功的图像,评论里感谢留言和有人提出的疑惑,博主也及时给出了解答,所以给了我这个程序应该很容易成功的错觉。

处理问题地思路十分清晰:

1、选择一张典型的光斑图像,裁掉多余暗色背景,只留下光斑(该步骤交给python,不用改变原图)

2、对图片进行灰度处理(这里很关键很关键!我就在这里踩坑了!

3、将图片上每个像素点转换成(x,y,z)形式并提取出来

4、将三个通道数值分别提取出来,依次放入数组X,Y,Z中。

5、以上述X,Y为坐标绘制面元图(网格化X,Y),将Z轴的数据仿真在网格化的二维XY图里。

案例给出的光斑图如下:

1

我信心满满地开始照搬,随后开始长达十个月(……)的自闭过程:)

一边测试一边疑惑,没人真的没有发现有bug嘛,你们就光搁那收藏点赞了是吧。

实际上认真弄不用那么久,不过我一向贯彻三天打鱼四天晒网的摆烂精神,中间还跑出去旅游沉迷打乙游看剧。

4

到这一步,大部人应该都没有什么问题。

显然,我不是大部分人:)

如果显示不出来图片,那应该是jupyter notebook或者其他编译器的动画设置出现问题。

在前面加上如下语句即可:

mport matplotlib.image as mping
matplotlib.use('TKAgg')

当我们成功修改尺寸后,可以看到光斑明显被集中放置在图片中央:

3

接着继续敲原代码。

这一步开始报错:

2

报错如图:

5

这指的是你的数据溢出了。查看roi.shape为(23, 40, 4),很明显roi具有三个单元,每个单元里分别有23、40、4个数据数,如果我们仅只用x,y两个列表去接收roi的数据,那多出去的z就没有处理了,所以报错了。

走的一些弯路

接下来就是我的茫茫是错之旅了,不感兴趣地可以折叠该部分或者直接拉到最后。正确的代码我放在最后了。
如果仅仅只是为了解决这一步的错误,可以改写成:

xs,ys,zs=np.indices(roi.shape)

没有继续报错了。对于上诉错误我先开始以为是作者手误,所以没有放在心上。

然后,就是我的茫茫是错之旅了。

建立面元图的时候,出现了新问题:

这里是说我的Z不是二维数据,所以没办法放在x,y张成的网格上。于是我开始想方设法的将Z轴的数据变成二维的,参考维度升级,后面突然意识到就算维度升级了,Z的数据长度也和X,Y的长度不一样。接下来的试错之路歪到学习插值法,不停修修补补Z轴的数据点,还做了平滑。最后得出的图像:


甚至还有当时的笔记备注。

遇到困难我就搁浅了。

灰度处理

直到后面(起码过了几个月了)很偶然的某天半夜失眠,我突发奇想地爬起来是看图像处理的课程(一直收藏但没看)。然后了解到了之前roi.shape里的(A,B,C)三个分别代表了高度,宽度和通道数。通道数是指的颜色数目。图片的色彩使用三原色或这四原色按不同比例混合而成。

我突然福至心灵,我在处理光斑的时候真的需要光斑那一处是什么颜色这样具体的信息嘛?我不是只需要强度就可以了吗,如果只要强度,黑白图也可以看得出强度啊。

……所以,我需要的信息可能只有(A,B)而不需要C?

那么试试看删掉C的信息呢?

那就是被忽略掉的灰度处理。然后,我找到了解决bug的正确道路(应该)。

比较简单粗暴的方式是:通过读取每个像素点的R,G,B值,进行灰度计算,将灰度值代替原有的值。

参考:RGB图像转换为灰度图像的原理_rgba 怎么转为灰色-CSDN博客

代码如下:

R, G, B = img[:,:,0], img[:,:,1], img[:,:,2] #每个通道的数字
imgGray = 0.2989 * R + 0.5870 * G + 0.1140 * B  # 灰度赋值

然后,问题解决了!附上我的拟合,拟合和原作者不一样因为我抓的边界点不同,改一下拟合的初始值应该可以修正过来。

8

这里有代码

最后,附上完整代码:

import numpy as np
import matplotlib
import matplotlib.image as mping
matplotlib.use('TKAgg')
import matplotlib.pyplot as plt
img=plt.imread(r"XXXX\XXX.JPG").astype(float) #填写你图片的位置
R, G, B = img[:,:,0], img[:,:,1], img[:,:,2] #每个通道的数字
imgGray = 0.2989 * R + 0.5870 * G + 0.1140 * B  # 灰度赋值
plt.ginput(2) #截取图片

将你选取的图片位置返回的点记住,赋给新列表,并进行坐标网格化处理,创建面元图。

roi=imgGray[167:205,350:390]
xNum,yNum = roi.shape #获取roi的维度
xAxis,yAxis = np.meshgrid(range(yNum),range(xNum)) #创建长度为xNum的自然数列
ax = plt.gca(projection='3d') #建立3D坐标轴
ax.plot_surface(xAxis,yAxis,roi) #创建面元图

plt.show()

进行数据拟合:

arr = np.max(roi,0)
x = np.arange(len(arr))
plt.plot(x,arr)

from scipy.optimize import curve_fit #规范一点可以写在开头
def gauss(x,a,b,c):
     return a*np.exp(-(x-b)**2/c**2)



abc, para = curve_fit(gauss,x,arr,[1.2, 0, 8])
 #即上式中的a,b,c
#np.array([89.72326971, 35.58522403, 20.86186403])
fitValue = gauss(x,abc[0],abc[1],abc[2]) #拟合值
plt.scatter(x,arr)

plt.plot(x,fitValue) #绘制拟合数据的曲线图
print(abc)
plt.show()