python3 全景图裁剪

需求:

1、将鱼眼全景图 转换为three.js 可加载的六面立方体图片

 

资料查阅:

1、目前就找到这个地方有、可能是为父搜索的姿势不对 -->前往

2、图片包含内容

 

使用到的 python 库:

1、numpy ---太大,这里用于处理图像矩阵变形,计算。
2、cv2  -- 太大, 只用到了 图像映射(将原始图像映射到变形后的矩阵。)
3、PIL --图片处理库,用于图片读写、储存、 矩阵转图片
4、

 

过程:

1、当然是先看别人写好的案例了。(自己去看,反正我是看不懂。见识浅薄)

大概解释一下我能看懂的部分吧。

1)获取到图片信息-》

2)将图片转为矩阵-》

3)把矩阵重新计算变为一张包含六个面的图片(这个东东也就只能看懂一丢丢,但是管他呢,能用就行)-》

4)将原始图片按照这个处理好的矩阵进行映射-》

5)图像保存------》》》》

6)图像裁剪成为六张独立的图(可以不考虑)

 

图片处理:

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()
View Code

 

图片裁剪:

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
View Code

 

 

这都是在上面的那个论坛上面别人写的,我复制的。

我这边的话,会直接存为单个文件,所以就不用重新在裁剪一次了。

速度的话,还算客可观、毕竟一张图片的大小决定了计算的效率。

 

posted @ 2023-07-25 16:05  睡到自然醒ccc  阅读(106)  评论(0编辑  收藏  举报