python|数字图像处理-Python实现BMP图片(位图)旋转-代码实例


目录

  • 正确实例
    • 代码片
    • 运行结果
  • 有问题的代码
    • 运行结果
  • 参考链接

正确实例 第一次写博客,记录自己的作业!不要直接照搬照抄哦!
前面的读BMP位图和显示图片信息的函数也是我自己写的,但是参考链接找不到了。
编译器:Spyder(Python3.7)、pycharm
原图:
python|数字图像处理-Python实现BMP图片(位图)旋转-代码实例
文章图片

代码片 主要算法就是利用极坐标的旋转公式(可以查看我在最后贴的参考链接),遍历新图的每个坐标,计算对应原图的坐标,再将对应的像素值复制到新图片像素矩阵中。
前面的部分需要有对BMP位图基础知识的了解。
函数代码:
#图片绕几何中心逆时针旋转angle度 def rotate(img, angle): H, W, C = img.shapeanglePi = angle * math.pi / 180.0 cosA = math.cos(anglePi) sinA = math.sin(anglePi)#计算四个顶点旋转后的值,最大差就是新图像的长和宽 vx,vy=[],[] for a in (0.5*H,-0.5*H): for b in (0.5*W,-0.5*W): vx.append(a*cosA+b*sinA) vy.append(-1*a*sinA+b*cosA) new_height = math.floor(max(vx)-min(vx))+1 new_width = math.floor(max(vy)-min(vy))+1 #下面是原博主求新长和宽的方法,我试验后发现当旋转角度大于90度时会 #出现不适配,感兴趣的同学可以试试 #new_height = math.ceil(H * np.cos(anglePi) + W * np.sin(anglePi)) #new_width = math.ceil(W * np.cos(anglePi) + H * np.sin(anglePi))out = np.zeros((new_height+1, new_width+1, C), dtype=int) #坐标偏移量 dx_back = 0.5 * W - 0.5 * new_width * cosA - 0.5 * new_height * sinA dy_back = 0.5 * H + 0.5 * new_width * sinA - 0.5 * new_height * cosA for y in range(new_height): for x in range(new_width): x0 =int( x * cosA + y * sinA + dx_back) y0 = int(y * cosA - x * sinA + dy_back) # 计算结果是这一范围内的x0,y0才是原始图像的坐标 if 0 < x0 < W and 0 < y0 < H: out[y, x] = img[y0, x0] return out

附上主函数和会用到的其他函数:
import numpy as np import struct import matplotlib.pyplot as plt import math import operator from operator import itemgetter#设置图片参数为全局变量 f_size=0 f_ofset=0 f_wide=0 f_height=0 f_bitcount=0def readInfo(f): ##读取文件头和信息头 f_type = str(f.read(2)) ##开头两字节为文件类型 file_size_byte = f.read(4) ##3-6字节是文件长度 f.seek(f.tell()+4) ##跳过四字节 file_ofset_byte = f.read(4)##偏移量 f.seek(f.tell()+4) ##跳过信息头长度 file_wide_byte = f.read(4) ##宽度 file_height_byte = f.read(4) ##高度 f.seek(f.tell()+2) ##跳过位平面数 file_bitcount_byte = f.read(4) ##每个像素占位#将读取的字节转换成指定类型 global f_size,f_ofset,f_wide,f_height,f_bitcount f_size,=struct.unpack('l',file_size_byte)#字节字符串转化为long f_ofset,=struct.unpack('l',file_ofset_byte) f_wide,=struct.unpack('l',file_wide_byte) f_height,=struct.unpack('l',file_height_byte) f_bitcount,=struct.unpack('i',file_bitcount_byte)#转为int print("类型:",f_type,"\n大小:",f_size,"\n位图数据偏移量:",f_ofset,"\n宽度:",f_wide,"\n高度:",f_height,"\n位图:",f_bitcount)def readImg(f): f.seek(54) #读取调色板 color_table=np.empty(shape=[256,4],dtype=int) for i in range(0,256): b = struct.unpack('B',f.read(1))[0]#integer g = struct.unpack('B',f.read(1))[0] r = struct.unpack('B',f.read(1))[0] alpha = struct.unpack('B',f.read(1))[0] color_table[i][0] = r color_table[i][1] = g color_table[i][2] = b color_table[i][3] = 255#读取数据部分 f.seek(f_ofset)#指针偏移 #256色图像是八位伪彩色图像,一个像素占一个字节 img = np.empty(shape=[f_height,f_wide,4],dtype=int) cout = 0 for y in range (0,f_height): for x in range(0,f_wide): cout = cout+1; index = struct.unpack('B',f.read(1))[0] img[f_height-y-1,x]=color_table[index] #行像素不是4的倍数要将填充的字节读取掉 while cout %4 !=0: #print(cout) f.read(1) cout = cout+1 return img def showImg(img): #显示图像 plt.imshow(img) plt.show()if __name__=='__main__': filename = 'D:\\数字图像处理\\彩色lena图像256色.BMP' f=open(filename,'rb') readInfo(f) initImage = readImg(f) iSRotate = rotate(initImage,30) showImg(iSRotate) f.close()

运行结果 python|数字图像处理-Python实现BMP图片(位图)旋转-代码实例
文章图片

有问题的代码 这一部分代码是我听了老师讲课之后(其实没怎么听)根据自己的想法写出来的,中间也花了很多心思,最后空穴的问题看有没有大佬能帮忙完善。但是最佳方法肯定还是根据新图找原图对应点,这种做法只是提供一种思路。
def rotate(image, angle): # 使用矩阵运算 x = [] y = [] for i in range(f_height): for j in range(f_wide): anglePi = angle * math.pi / 180.0 x.append(int(math.cos(anglePi) * i - math.sin(anglePi) * j + 0.5)) y.append(int(math.sin(anglePi) * i + math.cos(anglePi) * j + 0.5)) minX = min(x) maxX = max(x) minY = min(y) maxY = max(y) # 确定新图大小 height = maxX - minX + 1 width = maxY - minY + 1 iSRotate = np.empty(shape=[height, width, 4], dtype=int) for i in range(f_height): for j in range(f_wide): iSRotate[x[i * f_wide + j] - minX, y[i * f_wide + j] - minY] = image[i, j] #以下是我尝试进行的改进但是没有成功qaq '''#填充空穴,均值插值法 x3 = math.cos(anglePi)*(f_wide-1)-math.sin(anglePi)*(f_height-1)-minX y3 = math.sin(anglePi)*(f_wide-1)+math.cos(anglePi)*(f_height-1)-minY iSRotate2 = iSRotate for i in range(height-1): for j in range(width-1): if(iSRotate2[i,j].all()==0): avg = iSRotate[i-1,j]+iSRotate[i+1,j]+iSRotate[i,j-1]+iSRotate[i,j+1] iSRotate2[i,j] = avg'''# i>=-math.tan(anglePi)*j-minY and i<=1/math.tan(anglePi)*j-minY #and i>=1/math.tan(anglePi)*(j-x3)+y3 and i<=-math.tan(anglePi)*(j-x3)+y3 return iSRotate

运行结果 python|数字图像处理-Python实现BMP图片(位图)旋转-代码实例
文章图片

可以看到有很多转飞的空穴,因为是从原图找新图的对应点坐标,所以有一部分新图像素是找不到对应像素的
参考链接 【python|数字图像处理-Python实现BMP图片(位图)旋转-代码实例】链接: 参考链接.

    推荐阅读