python3 全景图裁剪
需求:
1、将鱼眼全景图 转换为three.js 可加载的六面立方体图片
资料查阅:
1、目前就找到这个地方有、可能是为父搜索的姿势不对 -->前往
2、图片包含内容
使用到的 python 库:
1、numpy ---太大,这里用于处理图像矩阵变形,计算。
2、cv2 -- 太大, 只用到了 图像映射(将原始图像映射到变形后的矩阵。)
3、PIL --图片处理库,用于图片读写、储存、 矩阵转图片
4、
过程:
1、当然是先看别人写好的案例了。(自己去看,反正我是看不懂。见识浅薄)
大概解释一下我能看懂的部分吧。
1)获取到图片信息-》
2)将图片转为矩阵-》
3)把矩阵重新计算变为一张包含六个面的图片(这个东东也就只能看懂一丢丢,但是管他呢,能用就行)-》
4)将原始图片按照这个处理好的矩阵进行映射-》
5)图像保存------》》》》
6)图像裁剪成为六张独立的图(可以不考虑)
图片处理:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import cv2 import numpy from numpy import pi from PIL import Image import sys import os.path import zipfile # Convert using an inverse transformation def generate_mapping_data(image_width): in_size = [image_width, int(image_width * 3 / 4)] #图像宽度数组、[总长、剪掉一条边后的总长] edge = in_size[0] / 4 # The length of each edge in pixels 总长1/4 # Create our numpy arrays out_pix = numpy.zeros((in_size[1], in_size[0], 2), dtype="f4") #用于记录 球体切割成功后的数组记录 # 生成2维空数组 【(图像剩余宽度、图像宽度、2维数组),参数类型=f4】 -------预测是为后期处理像素坐标点 xyz = numpy.zeros((int(in_size[1] * in_size[0] / 2), 3), dtype="f4") #记录像素点的初始值 # 生成3维空数组【图像剩余宽度 * 图片宽度 / 2,3维数组】,参数类型 = f4 vals = numpy.zeros((int(in_size[1] * in_size[0] / 2), 3), dtype="i4") # 做球体转换用的矩阵 # 生成3维空数组【图像剩余宽度 * 图片宽度 / 2,3维数组】,参数类型 = f4 # Much faster to use an arange when we assign to to vals start, end = 0, 0 # 创建两个初始值 rng_1 = numpy.arange(0, edge * 3) # 创建连续元素(列表)0~ 单个边长 * 3 rng_2 = numpy.arange(edge, edge * 2) # 创建连续元素(列表)单个边长~ 单个边长 * 2 for i in range(in_size[0]): # 循环总长度 ,记录像素不同点的信息 # 0: back # 1: left # 2: front # 3: right face = int(i / edge) #当前循环长度 / (1/4)总长 rng = rng_1 if face == 2 else rng_2 #当整除等于2 时,位置= 单边长度~总长的一半? || 其他时候、 位置= 0~总长(1/3) # print(face) end += len(rng) # 结束值 += 当前位置列表的长度 vals[start:end, 0] = rng # vals[start:end, 1] = i # vals[start:end, 2] = face # start = end # Top/bottom are special conditions j, i, face = vals.T # 矩阵转置 face[j < edge] = 4 # top ??? 这个没理解 face[j >= 2 * edge] = 5 # bottom ??? 这个没理解 # Convert to image xyz a = 2.0 * i / edge # b = 2.0 * j / edge one_arr = numpy.ones(len(a)) # 创建元素组,元素填充值为1, 长度为a的长度 for k in range(6): # 获取六面体的像素信息 face_idx = face == k #数组元素取值 face 矩阵内 值等于k的数组 # Using the face_idx version of each is 50% quicker one_arr_idx = one_arr[face_idx] # 取值 one_arr数组内 face == k 的值 a_idx = a[face_idx] # 取值 a 数组内 face == k 的值 b_idx = b[face_idx] # 取值 b 数组内 face == k 的值 if k == 0: vals_to_use = [-one_arr_idx, 1 - a_idx, 3 - b_idx] # [x=负one_arr_idx的值》?,y=1.0 - a_idx的值?,z = 3.0-b_idx的值?] elif k == 1: vals_to_use = [a_idx - 3, -one_arr_idx, 3 - b_idx] elif k == 2: vals_to_use = [one_arr_idx, a_idx - 5, 3 - b_idx] elif k == 3: vals_to_use = [7 - a_idx, one_arr_idx, 3- b_idx] elif k == 4: vals_to_use = [b_idx - 1, a_idx - 5, one_arr_idx] elif k == 5: vals_to_use = [5 - b_idx, a_idx - 5, -one_arr_idx] print(vals_to_use[0],len(vals_to_use[0])) xyz[face_idx] = numpy.array(vals_to_use).T #矩阵生成并转置 # cubemap = cv2.remap(numpy.array(imgIn), map_x_32, map_y_32, cv2.INTER_NEAREST) # 图片重新映射,以计算好的矩阵为参数 # imgOut = Image.fromarray(cubemap) # imgOut.save('E:\\新联国际\\地产项目\\python_jb\\Bath3.jpg'.split('.')[0]+"_out.png") # imgOut.show() # Convert to theta and pi x, y, z = xyz.T # 矩阵转置 theta = numpy.arctan2(y, x) # 元素所在象限? r = numpy.sqrt(x**2 + y**2) # 矩阵元素的平方根,开方 phi = numpy.arctan2(z, r) # 计算象限? # Source img coords # 原图坐标? uf = (2.0 * edge * (theta + pi) / pi) % in_size[0] # (2.0*图片4等分长度*())??? uf[uf==in_size[0]] = 0.0 # Wrap to pixel 0 (much faster than modulus) vf = (2.0 * edge * (pi / 2 - phi) / pi) # Mapping matrix out_pix[j, i, 0] = vf out_pix[j, i, 1] = uf map_x_32 = out_pix[:, :, 1] map_y_32 = out_pix[:, :, 0] return map_x_32, map_y_32 imgIn = Image.open('E:\\新联国际\\地产项目\\python_jb\\Bath3.jpg') inSize = imgIn.size map_x_32, map_y_32 = generate_mapping_data(inSize[0]) cubemap = cv2.remap(numpy.array(imgIn), map_x_32, map_y_32, cv2.INTER_NEAREST) # 图片重新映射,以计算好的矩阵为参数 imgOut = Image.fromarray(cubemap) # imgOut.save('E:\\新联国际\\地产项目\\python_jb\\Bath3.jpg'.split('.')[0]+"_out.png") imgOut.show()
图片裁剪:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
infile = 'E:\\新联国际\\地产项目\\python_jb\\Bath3.jpg' filename, original_extension = os.path.splitext(infile) file_extension = ".png" # name_map = [ \ ["", "", "posy", ""], ["negz", "negx", "posz", "posx"], ["", "", "negy", ""]] try: im = imgOut print(infile, im.format, "%dx%d" % im.size, im.mode) width, height = im.size cube_size = width / 4 filelist = [] for row in range(3): for col in range(4): if name_map[row][col] != "": sx = cube_size * col sy = cube_size * row fn = name_map[row][col] + file_extension filelist.append(fn) print("%s --> %s" % (str((sx, sy, sx + cube_size, sy + cube_size)), fn)) im.crop((sx, sy, sx + cube_size, sy + cube_size)).save(fn) zfname = filename + '.zip' print("Creating zipfile: " + zfname) zf = zipfile.ZipFile(zfname, mode='w') try: for fn in filelist: zf.write(fn) print("done") finally: zf.close() except IOError: pass
这都是在上面的那个论坛上面别人写的,我复制的。
我这边的话,会直接存为单个文件,所以就不用重新在裁剪一次了。
速度的话,还算客可观、毕竟一张图片的大小决定了计算的效率。