python图片处理常用操作笔记

萌新方便自己查询的笔记,记录一些常用的方法,不定时更新~

1. 静态图片操作笔记

安装库

安装

pip install numpy
pip install opencv-python

 

导入库

import numpy as np
import cv2

注:opencv中通过索引直接读取图片像素时,列在前行在后!即img[y][x]!
 

读写静态图片

注:如果图片文件名中含有中文,会导致出错,需要使用以下带中文路径的特殊写法。

从磁盘读取图片

img_path = "input.jpg"
# 读取单通道黑白图片
img = cv2.imread(img_path,0)
# 读取三通道彩色图片
img = cv2.imread(img_path,1)
# 读取四通道PNG图片,第四通道alpha为透明度
img_path = "input.png"
img = cv2.imread(img_path,-1)

读取带中文路径的图片

import numpy as np
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)

将图片写入磁盘

output_path = "output.jpg"
cv2.imwrite(output_path,img)

写入带中文路径的图片

import numpy as np
import os
cv2.imencode(os.path.splitext(output_path)[1], img)[1].tofile(output_path)

用cv2显示图片

# 允许图片自由缩放
window_name = "test window"
cv2.namedWindow(window_name,0);
# 显示图片
cv2.imshow(window_name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()

或者

cv2.imshow("1", img1)
cv2.imshow("2", img2)
cv2.waitKey(0)

然后按空格切换下一张

 

将彩色图转换为灰度图

注:与直接读入灰度图的效果不完全相同

img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

 

滤波器

根据具体需求选择不同的滤波器。

# 使用3x3的均值滤波器
img = cv2.blur(img, (3, 3))

# 中值滤波
img = cv2.medianBlur(img, 3)

# 高斯滤波
img = cv2.GaussianBlur(img,(3,3),0)

# 拉普拉斯滤波器
laplacian = cv2.Laplacian(srcImg, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)

# 自定义滤波器,样例为拉普拉斯滤波器
kernal = np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]])
img = cv2.filter2D(img, -1, kernal)

 

缩放图片的长宽

resize与reshape不同:
reshape是重塑矩阵形状,不改变数据总量,如将(2,3)改为(1,6)。
resize是任意尺度缩放图片,会改变矩阵包含的总元素数量。

# 设定新的图片长宽
new_size = (224,224)
# 缩放图片
img = cv2.resize(img,new_size)

对于高像素图片缩小,使用cv2可能会导致严重的锯齿产生,这种情况下可以使用Image库进行高质量图像缩放。

from PIL import Image
# 将图像从BGR空间转换到RGB空间,如果是三通道图像就去除A图层
(B, G, R, A) = cv2.split(img)
# 四颜色通道合并
img = cv2.merge([R,G,B,A])

# 修改为256x256
img = Image.fromarray(img)  
img = img.resize((256,256), Image.ANTIALIAS)
# 使用Image输出到磁盘
img.save(output_path)

 

保存8位png(更小的磁盘大小)

需要先转换为Image库的image格式

img.convert('P').save(img_path)

图片截取

等同于numpy的高维矩阵切片,如:

img = img[:200,100:,:]

 

颜色通道拆分与合并

# 三颜色通道拆分
(B, G, R) = cv2.split(img)
# 三颜色通道合并
img = cv2.merge([B,G,R])

# 四颜色通道拆分
(B, G, R, A) = cv2.split(img)
# 四颜色通道合并
img = cv2.merge([B,G,R,A])

 

直方图均衡化

# 对单通道使用,多通道需要先拆分再对每个通道分别均衡化
img = cv2.equalizeHist(img)

 

图片旋转与翻转

# 垂直翻转
img = cv2.flip(img,0)
# 水平翻转
img = cv2.flip(img,1)
# 垂直水平翻转/旋转180度
img = cv2.flip(img,-1)
# 左转90度
img = cv2.flip(cv2.transpose(img), 0)
# 右转90度
img = cv2.flip(cv2.transpose(img), 1)

任意角度旋转图片

import cv2
  
# Reading the image
image = cv2.imread('image.jpeg')
  
# Extracting height and width from 
# image shape
height, width = image.shape[:2]
  
# get the center coordinates of the
# image to create the 2D rotation
# matrix
center = (width/2, height/2)
  
# using cv2.getRotationMatrix2D() 
# to get the rotation matrix
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=90, scale=1)
  
# rotate the image using cv2.warpAffine 
# 90 degree anticlockwise
rotated_image = cv2.warpAffine(
    src=image, M=rotate_matrix, dsize=(width, height))
  
cv2.imshow("rotated image:", rotated_image)
cv2.imwrite('rotated_image.jpg', rotated_image)

形态学操作

# 定义核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))

# 膨胀
img = cv2.dilate(img,kernel,iterations=1)

# 腐蚀
img = cv2.erode(img,kernel,iterations=1)

 

画圆

# 画圆
cv2.circle(img, center, radius, (255, 0, 0), 1)
# 画矩形
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 1)

二值化

# 定义阈值
threshold = 50
# 固定阈值二值化
ret,img=cv2.threshold(gray_img,threshold,255,cv2.THRESH_BINARY_INV)

# 大津法
thresold, img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# 局部自适应二值化
binary = cv2.adaptiveThreshold(gray_img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,3, 5)

拼接图像

import cv2
import numpy as np

img1 = cv2.imread('1.png', 1)
img2 = cv2.imread('2.png', 1)

# 拼接图像
h, w = img1.shape[:2]
result = np.zeros([h, w*2, 3], dtype=img1.dtype)
result[0:h,0:w,:] = img1
result[0:h,w:2*w,:] = img2

# 给图像打标注文字
cv2.putText(result, f"1", (10, 30), cv2.FONT_ITALIC, 1.0, (0, 0, 255), 2)
cv2.putText(result, f"2", (w+10, 30), cv2.FONT_ITALIC, 1.0, (0, 0, 255), 2)

# 写入图像
cv2.imwrite('result.png', result)

使用mask为图像赋值

使用0与255的mask赋值图像

cv2.copyTo(src, mask, dist)

 

高维矩阵转置

用于机器学习输入。
将(length, width, 3)的彩色图片矩阵修改为(3, length, width)的形式。

tensor中的用法,需要导入torch包。

img = torch.tensor(img, dtype=torch.float32)
# 改变矩阵形状
img = img.permute(2, 0, 1)

 

对全图像素用指定中心聚类

# 寻找图像中每个像素对应的最近的聚类中心像素,然后统计每个聚类中心匹配到的像素数量
# 将图像和中心像素值转换为numpy数组,并调整它们的形状
img = np.array(img, dtype=np.float32)
centers = np.array(centers, dtype=np.float32).reshape(-1, 1, 1, 3)

# 计算每个像素与每个中心像素值的欧氏距离
diffs = np.linalg.norm(img - centers, axis=3)

# 找到每个像素与哪个中心像素值的距离最小
labels = np.argmin(diffs, axis=0)

# 计算每个中心像素值匹配到的像素数量
counts = np.bincount(labels.flatten(), minlength=len(centers))

二值图合并

cv2.bitwise_or(bin1, bin2)
cv2.bitwise_and(bin1, bin2)

连续绘制多条线段

match_img = cv2.polylines(match_img, points_list, True, 255, 3, cv2.LINE_AA)

2. 动态图片操作笔记

针对动态gif图像的操作

2.1 imageio(不如后面的PIL靠谱)

安装库

安装

pip install imageio

导入库

import imageio

读取gif图片

注:是mimread(),而不是imread()。

imgs = imageio.mimread("test.gif")
imgs = np.array(imgs)

此时imgs为包含所有numpy矩阵形式图片的一个列表,其中每一个元素都是一个numpy矩阵形式的图片。

写出gif图片

output_name = "output.gif"
imageio.mimsave(output_name, imgs, 'GIF')

2.2 PIL

导入库

import PIL.Image as Image

读取gif图片

imgs = Image.open(path)

写出gif图片

import cv2
import numpy as np
import PIL.Image as Image

img_lists = []
# 先把所有图片放入一个list
for xxx:
    img = cv2.imread(path)
    img_lists.append(Image.fromarray(img))

output_name = "output.gif"
# 单帧持续时间
duration = 200
# 保存gif
img_lists[0].save(output_name, save_all=True, append_images = img_lists, duration=duration)

无限循环

PIL保存gif图片时设置为loop=0即无限循环

3. 一些简单功能实现笔记

3.1 单色背景照片背景色替换

用于将背景为单色(如蓝色)的证件照片背景色替换为其它颜色(如白色),在人物几乎不含与背景同色衣服的情况下使用。
需要根据输出图片的效果自行调整阈值max_difference的大小。

import cv2
import numpy as np
from scipy.spatial.distance import cdist

# 输入文件名
input_img = 'input.jpg'
img = cv2.imread(input_img,1)
# 配置阈值,与取样点之间的最大相似值误差,根据输出效果调整
max_difference = 150
# 取出左上角第一个点作为取样点
sample = img[0][0]
# 将图片拉平用于计算
input_data = img.reshape((img.shape[0] * img.shape[1], 3))
# 计算所有图片与采样点之间的曼哈顿距离
differences = cdist(input_data, [sample], 'cityblock')
# 还原距离矩阵的形状,此时为单通道,仅包含距离
differences = differences.reshape((img.shape[0], img.shape[1]))

# 将背景替换为新的颜色,此处设置为白色
change = np.array([255,255,255])
# 深拷贝一个输入图片用于输出
output = img.copy()

for i in range(img.shape[0]):
	# 打印工作进度
	if i % 500 == 0:
		print(i,"/",img.shape[0])
	# 如果距离小于阈值,改变颜色
	for j in range(img.shape[1]):
		if differences[i][j] < max_difference:
			output[i][j] = change

# 输出文件名
output_name = 'output.jpg'
cv2.imwrite(output_name,output)

 

3.2 为图片增加透明度图层并自定义透明度

输入一个三通道彩色图像,手动为其添加一个透明度的第四通道,即alpha通道,自定义透明度数据,然后输出为png图像。

import numpy as np
import cv2
# 输入一个三通道图像
img = cv2.imread('test.jpg',1)
# 拆分颜色通道
(B, G, R) = cv2.split(img)
# 自定义一个初始全为0的透明度图层
A = np.zeros(B.shape, dtype="uint8")
# 自定义调整透明度,透明度在0-255之间取值
# 这里将图片的一部分透明度调整为155,其余部分保持为0用作示例
A[:70,:] = 155
# 将透明度图层并入四通道图像
img = cv2.merge([B, G, R, A])
# 输出png格式的图片
cv2.imwrite('output.png',img)

 

3.3 截图提取微信表情图片

将3.1与3.2的代码思路整合一下,从而实现利用截图获取微信聊天中的表情图片……愚蠢的微信表情图片居然不能直接选择保存到本地???,并且让程序自动去除截图中的背景,将原本透明的图片背景仍然输出为透明的状态从而实现盗别人的图片作为自己头像的邪恶目的

import numpy as np
import cv2
from scipy.spatial.distance import cdist

# config,配置参数,根据实际输出情况调整
# 在截图的四周切除百分之多少的边框
cut_percent = 4
# 配置阈值,与取样点之间的最大相似值误差
max_difference = 50
# 输入文件名
input_img = 'weixin_img.png'
# 输出文件名
output_name = 'output.png'


img = cv2.imread(input_img,1)
# 去除截图边缘边框(按照百分比切除)
img = img[int(img.shape[0]*(cut_percent/100)):int(img.shape[0]*(1-cut_percent/100)),\
		int(img.shape[1]*(cut_percent/100)):int(img.shape[1]*(1-cut_percent/100)),:]

# 取出左上角第一个点作为取样点
sample = img[0][0]
# 将图片拉平用于计算
input_data = img.reshape((img.shape[0] * img.shape[1], 3))
# 计算所有图片与采样点之间的曼哈顿距离
differences = cdist(input_data, [sample], 'cityblock')
# 还原距离矩阵的形状,此时为单通道,仅包含距离
differences = differences.reshape((img.shape[0], img.shape[1]))

# 创建透明图层,默认全透明
A = np.zeros(img.shape[:2], dtype="uint8")

for i in range(img.shape[0]):
	# 打印工作进度
	if i % 500 == 0:
		print(i,"/",img.shape[0])
	# 如果距离大于阈值,设置为不透明
	for j in range(img.shape[1]):
		if differences[i][j] > max_difference:		
			A[i][j] = 255

# 生成带有透明图层的四通道输出图片
(B, G, R) = cv2.split(img)
output = cv2.merge([B, G, R, A])

cv2.imwrite(output_name,output)

 

3.4 将彩色图转换为黑白线稿

转换为灰度图,通过拉普拉斯滤波器提取线稿轮廓,通过形态学操作的膨胀和腐蚀来连接结构和去除噪点,最后用二值化增强轮廓与减少噪点。
原图:
在这里插入图片描述

import cv2
import numpy as np

img_path = "input.png"
# 读取单通道黑白图片
img = cv2.imread(img_path,0)

# 拉普拉斯滤波器
kernal = np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]])
img = cv2.filter2D(img, -1, kernal)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
# 膨胀两次
img = cv2.dilate(img,kernel,iterations=2)

# 腐蚀两次
img = cv2.erode(img,kernel,iterations=2)

# 二值化
ret,img=cv2.threshold(img,50,255,cv2.THRESH_BINARY_INV)

# 输出
output_path = "output.jpg"
cv2.imwrite(output_path,img)

最终效果:
在这里插入图片描述

3.5 将彩色图转换为黑白线稿图像自适应增强亮度对比度

https://blog.51cto.com/u_15669955/5351337

3.6 使用mediapipe进行手检测

import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
import cv2
from google.protobuf.json_format import MessageToDict
import os

# 配置meidapipe
hand_drawing_utils = mp.solutions.drawing_utils  # 绘图工具
mp_hands = mp.solutions.hands  # 手部识别api
my_hands = mp_hands.Hands(static_image_mode = False)  # 获取手部识别类,默认开启跟踪模式

# 使用mediapipe进行推理
results = my_hands.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 解析meidapipe
multi_hand_landmarks = results.multi_hand_landmarks
multi_handedness = results.multi_handedness
for hand_id in range(len(multi_hand_landmarks)):
    # 得到当前手的信息
    hand_landmarks = multi_hand_landmarks[hand_id]
    handedness = multi_handedness[hand_id]
    # 得到手分类
    hand_type = MessageToDict(handedness)['classification'][0]['label']
    # 得到手关键点
    kpts = MessageToDict(hand_landmarks)['landmark']

3.7 匹配并找到透视转换关系

cv2.findHomography

https://blog.csdn.net/qq_36387683/article/details/98446442

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值