【CV\utils】OpenCV、PIL、FFmpeg 软件 & czi、tif、gif 等格式视频图像文件处理 || 代码合集

【start:2023.07.25】

1. OpenCV-python

1.1. 基础知识

不管是打开一个图像或者是接收矩阵生成一个图像,他们都应为dtype=“uint8”

# 不管是打开一个图像或者是接收矩阵生成一个图像他们都应为dtype=“uint8”
img = cv2.imread(_input, cv2.IMREAD_COLOR)  # 使用cv2打开图片
# 注意观察shape,如果有第三维还要看通道数
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY).astype("uint8")
out = out[:,:,0]*255
out = out.astype("uint8")
# print('img.shape[2]',img.shape[2])
# print('out.shape[2]',out.shape[2])

# 创建一个空白图片
line = 255*np.ones((5, 256), np.uint8)

line = cv2.resize(line, (10, 256))
img = cv2.resize(img, (256, 256))
out = cv2.resize(out, (256, 256))
# 图片横向拼接
outs = cv2.hconcat([ img, line, out])

cv2.imwrite('result/result.png',out)
# cv2.imshow('img',img)
# cv2.imshow('out',out)
cv2.imshow('outs',outs)
cv2.waitKey(0)

2. PIL-python

2.1. 基础知识

2.2. PIL和Opencv互转

import cv2
import cv2 as cv
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

def PIL_Opencv(image):
    image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
    return image

def Opencv_PIL(image):
    image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    return image

3. FFmpeg插件

【Python】ffmpeg的安装配置和python中使用ffmpy(保姆级图文)
https://blog.csdn.net/u011027547/article/details/122490254

ffmpeg官网
https://ffmpeg.org/download.html
https://www.gyan.dev/ffmpeg/builds/
https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z

3.1. 万能看图

用ffplay打开视频&图片:

E:\lxq\ffmpeg-6.0-full_build\bin\ffplay.exe

3.2. 拷贝视频

import subprocess

## 拷贝前询问是否覆盖
cmd = f"ffmpeg -i {out_mp4} -c copy {out_mp4_.replace('data/out_put', new_folder_path)}"
subprocess.run(cmd.split())

# 拷贝时默认覆盖
cmd = f"ffmpeg -y -i {out_mp4} -c copy {out_mp4_.replace('data/out_put', new_folder_path)}"
subprocess.run(cmd.split())

3.3. 切割视频

# trim video to shorter seconds
# ffmpeg  -ss 00:00:05  -to 00:00:10 -y -i data/examples/bella_porch.mp4 -c copy data/out_put/video_mp4.mp4
cmd = f"ffmpeg  -ss {min_time} -to {max_time} -y -i {video_input} -c copy {video_mp4}"
subprocess.run(cmd.split())

3.4. 横向拼接视频

cmd = f"ffmpeg -y -i {driving_mp4} -i {out_mp4} -filter_complex hstack=inputs=2 {final_mp4}"
subprocess.run(cmd.split())

3.5. 合并视频

ffmpeg -f concat -safe 0 -i I:\\Su_Lab\\video\\concat.txt -c copy I:\\Su_Lab\\video\\output.mp4

4. 图像格式转换

4.1. img to uint8

也可以把数组转换成图像
转换时要注意:
灰度值的最大值可能256或25536,如果选错uint类型,超出最大值的部分会被“削去”,从而“白”得刺眼

可以直接用PIL库转换

from PIL import Image
Image.fromarray(np.uint8(img))

当img元素的范围是0-1之间时,要乘255,将其转换为0-255

Image.fromarray(np.uint8(255*img))

也可以用下述代码转换

'''
img_to_uint8

trans img's formats(including unit16, float64) to uint8, so the new img can best match opencv plugin.

'''

def get_max(img):
    maxx = max(map(max, img))
    print('maxx=',maxx)
    return maxx

def print_info(img):
    print('img.shape:',img.shape)
    print('img.dtype',img.dtype)
    get_max(img)


def img_to_uint8(raw_img):
    
    # trans to uint8
    print('****begin img_to_uint8')

    # raw_img = frames[0]
    # raw_img=Sobel()

    print('raw img.dtype:',raw_img.dtype)
    maxx = max(map(max, raw_img))
    print('raw maxx:',maxx) 
    plt.imshow(raw_img)
    
    img = raw_img
    if img.dtype=='uint8':
        print('raw = uint8')
        img_target_8 = img
    elif img.dtype=='uint16':
        print('raw = uint16')
        img = img/256

        # 归256化,防止数值太小而丢失数值
        maxx = max(map(max, img))
        img = img*256/maxx
        
        img_target_8=(img).astype(np.uint8)  
    elif img.dtype=='float64':
        print('raw = float64')
        img=(img).astype(np.uint16)  #
        img_target_8 = img_to_uint8(img)

    else:
        print('trans format wrong')
    img = img_target_8
    print('new img.dtype:',img.dtype)
    maxx = max(map(max, img))
    print('new maxx:',maxx) 
    plt.imshow(img)

    return img

4.2. tif2jpg

'''
tif gen jpg

use gen_jpg function to generate a jpg picture in appointed file, 
use gen_all_jpg_in_flie function to generate all jpg in a big file_box.

'''

import numpy as np
import cv2 as  cv
from matplotlib import pyplot as plt
import glob

path = 'D:\\JoeOffice\\jupyter_notebook\\computer_vision\\small_object_track\\H2b_GFP_cell_track\\Fluo-N2DL-HeLa\\Fluo-N2DL-HeLa'

def gen_jpg(path):
    # path = r'D:\JoeOffice\jupyter_notebook\computer_vision\small_object_track\H2b_GFP_cell_track\Fluo-N2DL-HeLa\Fluo-N2DL-HeLa\01\t000.tif'
    jpg_name = path.split('\\')[-1].replace('.tif','.jpg')

    # 加载彩色灰度图像
    img = cv.imdecode(np.fromfile(path, dtype=np.uint8), -1)

    #图像编码格式转换
    img=(img/256).astype(np.uint8)  
    print(img.dtype)
    print(img)

    # 二值化
    imgray = img
    ret, thresh = cv.threshold(imgray, 130, 255,  cv.THRESH_BINARY)
    plt.imshow(thresh, cmap = None, interpolation = 'bicubic') 
    # plt.show()

    # 转换成RGB图像
    img_jpg =  cv.cvtColor(thresh, cv.COLOR_GRAY2RGB);
    
    plt.imshow(img_jpg, cmap = None, interpolation = 'bicubic') 
    plt.axis('off')   # 去坐标轴
    plt.xticks([])    # 去 x 轴刻度
    plt.yticks([])    # 去 y 轴刻度
    save_path = 'D:\JoeOffice\jupyter_notebook\computer_vision\small_object_track\H2b_GFP_cell_track\my_fluo_img\\'+jpg_name

    # # 仅保存
    # plt.savefig(save_path, bbox_inches='tight')
    
    # 仅展示
    plt.show()


def gen_all_jpg_in_flie(image_path):
    print('open')
    print(image_path + '\*.tif')
    # print(glob.glob(image_path + '\*.tif'))
    image_name_box = glob.glob(image_path + '\*.tif')
    for index, jpg_file in enumerate(image_name_box):
        print(index, jpg_file)
        if index <2:
            gen_jpg(jpg_file)
        # gen_jpg(jpg_file)

gen_all_jpg_in_flie(path + r'\01')

4.3. czi2tif

import czifile
path='xxx.czi'

# trans czi to to tif img
czifile.czi2tif(path)

4.4. 单通道图片生成三通道图片

'''
单通道->三通道
'''
import os
import cv2
import numpy as np
import PIL.Image as Image
import os
#os.environ['CUDA_VISIBLE_DEVICES'] = '2'
img_path='D:\JoeOffice\jupyter_notebook\computer_vision\segmentation\pytorch-UNet-master\labelme-main\examples\semantic_segmentation\img_4\\'
save_img_path='D:\JoeOffice\jupyter_notebook\computer_vision\segmentation\pytorch-UNet-master\labelme-main\examples\semantic_segmentation\img_3\\'
for img_name in os.listdir(img_path):
   image=Image.open(img_path+img_name)
   if len(image.split())==1: #查看通道数
       print(len(image.split()))
       print(img_path+img_name)
       img = cv2.imread(img_path + img_name)
       gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
       img2 = np.zeros_like(img)
       img2[:, :, 0] = gray
       img2[:, :, 1] = gray
       img2[:, :, 2] = gray
       img_name = img_name.replace('png', 'jpg')
       cv2.imwrite(save_img_path + img_name, img2)
       image = Image.open(save_img_path + img_name)
       print(len(image.split()))
   elif len(image.split())==4: #查看通道数
       print(len(image.split()))
       print(img_path+img_name)
       img = cv2.imread(img_path+img_name)
       gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
       img2 = np.zeros_like(img)
       img2[:,:,0] = gray
       img2[:,:,1] = gray
       img2[:,:,2] = gray
       img_name = img_name.replace('png','jpg')
       cv2.imwrite(save_img_path+img_name, img2)
       image=Image.open(save_img_path+img_name)
       print(len(image.split()))
   else:
       print(len(image.split()))
       print('road != 1,4')
       image.save(save_img_path+img_name)

'''
单通道->三通道
'''
#img_src = np.expand_dims(img_src, axis=2)
#img_src = np.concatenate((img_src, img_src, img_src), axis=-1)

5. 视频格式转换

5.1. czi

5.1.1. czi2gif

import numpy as np
import imageio
from czifile import CziFile
'''
czi转gif
https://pypi.org/project/czifile/#files

'''
def czi_to_gif(czi_path, gif_path, fps=10):
    with CziFile(czi_path) as czi:
        # Read the CZI file
        image_array = czi.asarray()

    # print(image_array)
    print(image_array.shape)
    
    # Convert CZI image array to GIF image sequence
    image_sequence = []
    for t in range(image_array.shape[0]):
        # Select a single time point
        frame = image_array[t][0,0,:,:,0]
        # Normalize pixel values to 0-255
        frame = img_to_uint8(frame)
        # Append to image sequence
        image_sequence.append(frame)

    # Save as GIF file
    imageio.mimsave(gif_path, image_sequence, fps=fps)

import glob
import os
in_folder = os.path.join(r'D:\JoeOffice\jupyter_notebook\computer_vision\instance_segmentation\MultiStar-main\datagen\data\PEG\czi','*.czi')
czi_paths = glob.glob(in_folder)
print(czi_paths)
for czi_path in czi_paths:
    gif_path = czi_path.replace('czi', 'gif')
    czi_to_gif(czi_path, gif_path, fps=10)

5.1.2. czi2tif

# czi2tif
import czifile
path=r'E:\dataset\PEG\Image 7 Block 2_SIM.czi'

# trans czi to to tif img
czifile.czi2tif(path)

5.2. tif

5.2.1. tif帧数+尺寸查询

# tif帧数+尺寸查询
import tifffile

# 打开TIFF视频文件
video_path = r'E:\dataset\PEG\block2sim.tif'
video = tifffile.TiffFile(video_path)

# 获取视频的帧数
num_frames = len(video.pages)

# 获取视频的形状(shape)即每帧数据的维度
shape_of_frame = video.pages[0].shape

# 输出帧数和形状
print(f"TIFF视频帧数:{num_frames} 帧")
print(f"每帧数据的形状(shape):{shape_of_frame}")

# 关闭文件
video.close()

5.2.2. 查询tif文件的结构

在某些情况下,一个TIFF文件可能同时包含"Pages"(页)和"Series"(系列)。这是由于TIFF格式的灵活性和多功能性。

  1. Pages(页):
    "Pages"是TIFF文件的基本组成单位,每个页可以包含一个独立的图像或数据块。这种情况下,TIFF文件就类似于一个多页文档,每个页可以看作是其中的一页。这种用法常见于单页扫描的TIFF文档或者将多个单页图像保存在一个文件中的情况。

  2. Series(系列):
    "Series"是用于组织多维数据或时间序列数据的一种机制。每个系列可以包含多个页,每个页代表一个相关的数据时间步或切片。这种用法通常用于科学和地理空间数据,如卫星图像时间序列或者多维医学图像数据。

为了更好地组织和表示多维或时间相关的数据,有时会在一个TIFF文件中同时使用"Pages"和"Series"。例如,假设一个实验生成了100个时间步的数据,并将每个时间步的数据保存在单独的页(Pages)中,那么整个实验就可以被组织成一个包含100个系列(Series)的TIFF文件,其中每个系列代表一个时间步。这样的组织方式既能保持TIFF文件的结构完整性,又可以方便地访问和处理多个时间步的数据。

需要注意的是,并非所有的TIFF文件都同时使用"Pages"和"Series"。TIFF格式的使用可以根据数据类型、生成方式和使用场景而异。在处理TIFF文件时,最好先了解其具体结构和组织方式,以便正确地读取和处理其中的数据。

import tifffile as tf

def print_tiff_info(tiff_file_path):
    with tf.TiffFile(tiff_file_path) as tif:
        # Print basic information
        print("TIFF File Information:")
        print(f"tif: {tif}")
        print(f"Filename: {tif.filename}")
        print(f"Number of pages: {len(tif.pages)}")
        print(f"tif: {tif.series}")

if __name__ == "__main__":
    # tiff_file_path = r"D:\JoeOffice\jupyter_notebook\computer_vision\SR\3D-RCAN-master\data\rcan\test\4-after_4_PEG-FRAP.tif"  # 替换为你的TIFF文件路径
    tiff_file_path = r"D:\JoeOffice\jupyter_notebook\computer_vision\SR\3D-RCAN-master\data\rcan\input\5-8%_PEG-normal_media.tif"  # 替换为你的TIFF文件路径
    print_tiff_info(tiff_file_path)

5.2.3. tif视频时长+尺寸裁剪

#  tif视频时长+尺寸裁剪
import tifffile

# 打开TIFF视频文件
video_path = r'E:\dataset\PEG\block2sim.tif'
video = tifffile.TiffFile(video_path)

# 获取视频的帧数
num_frames = len(video.pages)

# 确保要提取的帧范围在有效范围内
start_frame = 10
end_frame = 30
if start_frame < 1:
    start_frame = 1
if end_frame > num_frames:
    end_frame = num_frames

# 逐帧提取并保存
output_path = r'E:\dataset\PEG\block2sim_crop.tif'
cropped_frames = []

for frame_number in range(start_frame - 1, end_frame):  # 注意索引从0开始
    frame_data = video.pages[frame_number].asarray()
    if frame_number == start_frame-1:
        print(frame_data.shape)
        w = frame_data.shape[0]
        h = frame_data.shape[1]
        print(w,h)
        a = 0.3
        b = 1-a
        x1 = int(a*w)
        x2 = int(b*w)
        y1 = int(a*h)
        y2 = int(b*h)
    cropped_frame = frame_data[x1:x2, y1:y2]  # 裁剪为左上角的256x256尺寸
    cropped_frames.append(cropped_frame)

# 将裁剪后的帧保存为新的TIFF文件
tifffile.imwrite(output_path, cropped_frames)

# 关闭文件
video.close()

5.2.4. tif与gif互转

import imageio
import os
import numpy as np
'''
gif和tif互转
'''
def gif_to_tiff_video(gif_path, tiff_video_output_path, target_format):
    try:
        gif_images = imageio.mimread(gif_path)
    except FileNotFoundError:
        print("找不到 GIF 文件:", gif_path)
        return

    # 逐帧保存为图像序列
    for i, gif_image in enumerate(gif_images):
        tiff_frame_output_path = f"{tiff_video_output_path}_{i}.tif"
        imageio.imwrite(tiff_frame_output_path, gif_image, format=target_format)    
    
    # 将图像序列合并为视频
    if target_format == 'tif':
        with imageio.get_writer(tiff_video_output_path, format=target_format) as writer:
            whole_tiff_file = [0 for x in range(len(gif_images))]
            for i in range(len(gif_images)):
                tiff_frame_path = f"{tiff_video_output_path}_{i}.tif"
                tiff_frame_image = imageio.imread(tiff_frame_path)
                # 注意,这里要把tiff_frame_image整理好后,一次性传入writer中,这样返回的tif文件的格式就会是多个pages和一个series;如果分多次传入,则会有多个series,不符合tif文件的常态
                whole_tiff_file[i] = tiff_frame_image[:,:,0]
            writer.append_data(whole_tiff_file)
    elif target_format == 'gif':  
        with imageio.get_writer(tiff_video_output_path, format=target_format) as writer:
            for i in range(len(gif_images)):
                tiff_frame_path = f"{tiff_video_output_path}_{i}.tif"
                tiff_frame_image = imageio.imread(tiff_frame_path)
                # writer.append_data(np.expand_dims(tiff_frame_image[:,:,0], axis=0))
                # writer.append_data(tiff_frame_image[:,:,0])
                writer.append_data(tiff_frame_image)

    # 删除临时的TIFF图像序列文件
    for i in range(len(gif_images)):
        tiff_frame_path = f"{tiff_video_output_path}_{i}.tif"
        if os.path.exists(tiff_frame_path):
            os.remove(tiff_frame_path)

    print("TIFF视频转换完成!")

# 使用示例
if __name__ == "__main__":
    # target_format为output的格式,可取'gif','tif'
    target_format='tif'
    gif_file_path = r"D:\JoeOffice\jupyter_notebook\computer_vision\SR\3D-RCAN-master\data\rcan\test\4-after_4_PEG-FRAP.gif" 
    tiff_video_output_path = r"D:\JoeOffice\jupyter_notebook\computer_vision\SR\3D-RCAN-master\data\rcan\test\4-after_4_PEG-FRAP." + target_format
    
    gif_to_tiff_video(gif_file_path, tiff_video_output_path, target_format=target_format) 

6. 图像生成视频

6.1. 生成标准编号

生成长度一致的编号,不足长度的地方用“0”补齐

path_prefix = 'D:\JoeOffice\jupyter_notebook\computer_vision\particle_track\PEG\PEG_small_cut\PEG_small_cut'
        def saveImg_with_regularIndex(path_prefix):
            len_index_name = 4
            if len(str(i))<=len_index_name:
                len_index_offset = (len_index_name-len(str(i)))*'0'+str(i)
                save_path = path_prefix + len_index_offset
                plt.savefig(save_path, bbox_inches='tight',pad_inches = 0 )
                plt.show()
            else:
                save_path = path_prefix + str(i)
                plt.savefig(save_path, bbox_inches='tight',pad_inches = 0 )
                plt.show()
        
        saveImg_with_regularIndex(path_prefix)

6.2. img2gif

把一个文件夹里的所有图片按一定顺序制作成gif

import imageio, os, sys
'''
img gen gif
'''
def png_gif(path):
    # 需要将文件规范命名
    png_lst = os.listdir(path)
    frames = []
    for i in png_lst:
        frames.append(imageio.imread(path + i))
    imageio.mimsave("new_gif.gif", frames, 'GIF', duration=0.2)

def main():
    # 注意路径后要加两条斜杠
    path = r'D:\JoeOffice\jupyter_notebook\math_science\deeplearning_maozhiping\Possion_2D_demo\Possion_2D_demo_test\Output_iter_pic\\'
    png_gif(path)
    
if __name__=="__main__":
    main()    

注意,上面的函数有一个bug,os.listdir(path)会把60插入到600之前
解决方法:将原来文件规范命名,如:当最大值是三位数时,10改成010,20改成020

【ref】os.listdir(path)避坑指南

6.3. cut img

截取图片的一小块,并制作成gif


'''
cut img and gen gif

'''
import matplotlib as mpl
import matplotlib.pyplot as plt
import imageio, os, sys

def png_gif(path):
    # 需要将文件规范命名
    png_lst = os.listdir(path)
    frames = []
    i = 0
    for png_name in png_lst:
        
        print(png_name)
        pic = imageio.imread(path + png_name)
        pic_cut = pic[30:180,170:320,:]
        blank = pic*0
        blank[30:180,170:320,:] = pic_cut
        
        cv2.imshow('pic', pic)
        cv2.imshow('blank', blank)
        cv2.imshow('pic_cut', pic_cut)
        # cv2.waitKey(0)

        plt.axis('off')
        plt.imshow(blank)
        # print(pic.shape)

        len_step_name = 3
        if len(str(i))<=len_step_name:
            len_offset = (len_step_name-len(str(i)))*'0'+str(i)
            save_path_img_fliter = r'D:\JoeOffice\jupyter_notebook\computer_vision\particle_track\PEG\PEG_fliter_small_cut_img\\'+'PEG_fliter_small_cut_' + len_offset
            plt.savefig(save_path_img_fliter)
        else:
            save_path_img_fliter = r'D:\JoeOffice\jupyter_notebook\computer_vision\particle_track\PEG\PEG_fliter_small_cut_img\\'+'PEG_fliter_small_cut_' + str(i)
            plt.savefig(save_path_img_fliter)

        plt.savefig(save_path_img_fliter, bbox_inches='tight',pad_inches = 0)

        i=i+1   

def main():
    # 注意路径后要加两条斜杠
    path = 'D:\JoeOffice\jupyter_notebook\computer_vision\particle_track\PEG\PEG_fliter_img_less\\'
    png_gif(path)
    
if __name__=="__main__":
    main()    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值