深度学习中基于python的预处理和图像扩增方法

图像预处理及扩增

  • 判断图片是否为灰度图片
  • 批量给图片文件重命名
    • 给一批文件重命名
    • 把一批文件顺序打乱重命名
  • 图像旋转/翻转
  • 将图像和对应的xml标签文件都翻转
  • 将目标所在区域裁剪出来
    • 方法一
    • 方法二:
    • 方法三
  • 裁剪并纠偏
  • 图像扩增方法合集(对单张图片)

容易出现的报错:

cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:692: error: (-2:Unspecified error) could not find a writer for the specified extension in function 'cv::imwrite_'

错误原因通常为保存的路径不正确:

cv2.imwrite('./crop_images/origin_imgs', roi)

应改为:

cv2.imwrite(os.path.join('./crop_images/origin_imgs', img_name), roi)

即第一个参数应该写到文件的名称,而不能只写到文件夹就停止。

判断图片是否为灰度图片

灰度图片和黑白图片有些相似,但并不完全相同。

灰度图片是指每个像素点的颜色由灰度值来表示,通常使用8位无符号整数(0-255)表示。灰度图像中的每个像素点可能具有不同的灰度值,因此图像中可能会有许多不同的灰度级别。

黑白图片通常指的是二值图像,其中只有两种像素值,通常是黑色和白色。黑白图像中的每个像素点只有两种可能的取值,因此图像中只有两个灰度级别。

虽然灰度图像和黑白图像都只是使用灰度值来表示图像中的像素点,但它们在像素的取值范围和数量上有所不同。

# 黑白照片(灰度图)识别
def isGrayMap(img, threshold = 15):
    """
    入参:
    img:PIL读入的图像
    threshold:判断阈值,图片3个通道间差的方差均值小于阈值则判断为灰度图。
    阈值设置的越小,容忍出现彩色面积越小;设置的越大,那么就可以容忍出现一定面积的彩色,例如微博截图。
    如果阈值设置的过小,某些灰度图片会被漏检,这是因为某些黑白照片存在偏色,例如发黄的黑白老照片、
    噪声干扰导致灰度图不同通道间值出现偏差(理论上真正的灰度图是RGB三个通道的值完全相等或者只有一个通道,
    然而实际上各通道间像素值略微有偏差看起来仍是灰度图)
    出参:
    bool值
    """
    if len(img.getbands()) == 1:
        return True
    img1 = np.asarray(img.getchannel(channel=0), dtype=np.int16)
    img2 = np.asarray(img.getchannel(channel=1), dtype=np.int16)
    img3 = np.asarray(img.getchannel(channel=2), dtype=np.int16)
    diff1 = (img1 - img2).var()
    diff2 = (img2 - img3).var()
    diff3 = (img3 - img1).var()
    diff_sum = (diff1 + diff2 + diff3) / 3.0
    if diff_sum <= threshold:
        return True
    else:
        return False

参考

批量给图片文件重命名

给一批文件重命名

问题1:使用os.path.join()函数合并路径的时候,只显示后面的。
原因:使用os.path.join(r’D:\datasets\new_name’, “/1000” + str(i) + “.jpg”)

os.path.join()函数中可以传入多个路径: 会从第一个以”/”开头的参数开始拼接,之前的参数全部丢弃。
以上一种情况为先。在上一种情况确保情况下,若出现”./”开头的参数,会从”./”开头的参数的上一个参数开始拼接

注意下面代码中的os.rename(old_name, new_name)是对原始文件直接操作,会导致原始文件消失,如果要保留原始文件,使用shutil.copy(old_name, new_name)。

# 日期:  2023/4/22 11:47
import os

root_path = r'D:\datasets\1osr_original_img'

if os.path.exists(root_path):
    i = 1
    for filename in os.listdir(root_path):
        # 把图像改名
        old_name = os.path.join(root_path, filename)
        # 保证图片文件名称位数一致
        lens = 5 - len(str(i))
        new_name = os.path.join(root_path, "1" + "0"*lens + str(i) + ".jpg")  # 100001
        # 当文件不存在的时候创建,否则会报错:当文件已存在时,无法创建该文件。
        if not os.path.exists(new_name):
            os.rename(old_name, new_name)
        i += 1

        # 记录修改过程
        filelist = []
        if old_name != new_name:
            filelist.append('Old: ' + old_name)
            filelist.append('New: ' + new_name)

            f = open("rename_log.txt", "a")
            for file in filelist:
                f.write(file + '\n')

            f.close()
    print('OK')
else:
    print("路径不存在!")


注意:使用该代码处理文件会删除原来的图片,只保存新的图片。
操作有风险,所以可以记录修改过程。

参考

把一批文件顺序打乱重命名

# 日期:  2023/4/22 11:47
import os
import random

root_path = './crop_images/origin_imgs1'
save_path = './crop_images/origin_imgs'

if os.path.exists(root_path):
    lst = []
    for filename in os.listdir(root_path):
        i = random.randint(1, 242)
        while i in lst:
            i = random.randint(1, 242)
        lst.append(i)
        # 把图像改名
        old_name = os.path.join(root_path, filename)
        # 保证图片文件名称位数一致
        lens = 5 - len(str(i))
        new_name = os.path.join(save_path, "1" + "0" * (lens - 1) + str(i) + ".jpg")  # 100001
        # 当文件不存在的时候创建,否则会报错:当文件已存在时,无法创建该文件。
        if os.path.exists(new_name):
            print('文件名已存在。')
        else:
            os.rename(old_name, new_name)
        # i += 1

        # 记录修改过程
        filelist = []
        if old_name != new_name:
            filelist.append('Old: ' + old_name)
            filelist.append('New: ' + new_name)

            f = open("rename_log1.txt", "a")
            for file in filelist:
                f.write(file + '\n')

            f.close()
    print('OK')
else:
    print("路径不存在!")


图像旋转/翻转

# 日期:  2023/4/21 20:02
import cv2
import os

import numpy as np
from PIL import Image

root_path = r'D:\datasets\osr_original_img'

for filename in os.listdir(root_path):
    img_path = os.path.join(root_path, filename)
    angle = 270

    # 旋转方式
    # 1
    times = angle // 90
    img = cv2.imread(img_path)  # 生成的是numpy.ndarray,为ndarray多维数组类型,(H,W,C)
    img = np.rot90(img, k=times, axes=(0, 1))  # 对图像矩阵顺时针旋转90度,得到的像素与原来不同,变为H,W,与手机和电脑里对照片的旋转功能相同,如果想要顺时针,k设置为负数
    # 旋转后的图片的保存路径
    if angle == 90:
        new_name = filename.split('.')[0] + '_090.jpg'
    else:
        new_name = filename.split('.')[0] + '_{}.jpg'.format(angle)

    save_path = '../datasets/np rot{}/'.format(angle) + new_name
    # 使用cv2库保存图片,直接对矩阵保存就行
    cv2.imwrite(save_path, img)  # 保存旋转后的图像

    # # 2
    # img = Image.open(img_path)  # 生成的是PIL.JpegImagePlugin.JpegImageFile,(W,H)
    # img = img.transpose(Image.ROTATE_180)  # 引用固定的常量值,得到的像素与原来不同,变为H,W,与手机和电脑里对照片的旋转功能相同

    # 3
    # img = Image.open(img_path)  # 生成的是PIL.JpegImagePlugin.JpegImageFile,(W,H)
    # img = img.rotate(angle)  # 自定义旋转度数,得到的图片的像素与原来一样,都是W,H。逆时针旋转,如果需要顺时针加负号

    # # 旋转后的图片的保存路径
    # if angle == 90:
    #     new_name = filename.split('.')[0] + '_090.jpg'
    # else:
    #     new_name = filename.split('.')[0] + '_{}.jpg'.format(angle)
    #
    # save_path = '../datasets/rotate{}/'.format(angle) + new_name
    # # 使用Image库保存图片
    # img.save(save_path)

关于图像的旋转,有时候容易出现理解偏差,rotate是旋转,Transpose是变换位置,本文用翻转来指代。这两个功能的说明如下:

img.rotate(90) 是旋转90度, 这里要注意,只是对于图像内容进行旋转,图片文件本身(或者可以理解为画布)并不会旋转。
Image.Transpose.ROTATE_90,是翻转90度,通过执行这条语句,整个画布才会翻转。

在使用NumPy库中的np.rot90函数时,第二个参数k表示旋转的次数,如果k是正整数,则将数组旋转k次,如果k是负整数,则将数组逆时针旋转abs(k)次。
而第三个参数axes表示要交换的轴。默认情况下,将交换前两个轴。例如,对于二维数组,将交换第一维和第二维。在这种情况下,不需要指定第三个参数。
但是,当处理的数组不是二维数组时,就需要指定axes参数。在这种情况下,axes应该是一个长度为2的元组,用于指定要交换的轴。例如,在三维数组中,可以将第一维和第二维交换,而第三维保持不变,可以使用axes=(1,0)。
在代码中,-1作为axes参数的值。在这种情况下,-1表示最后一个轴。因此,np.rot90函数将沿着数组的最后一个轴旋转。这相当于在二维数组中,将第一维和第二维交换。

参考1
参考2
参考3
参考4

将图像和对应的xml标签文件都翻转

注释部分是垂直翻转,下面的是水平翻转。

flip_bbox_horizontal 函数的作用是对 XML 标注文件中的矩形框坐标进行水平翻转,并将修改后的标注文件保存到指定路径下。
具体而言,该函数首先使用 ET.parse 函数对传入的 XML 文件进行解析,并获取 XML 文件的根节点。然后,它遍历根节点下的所有 object 节点,对每个节点下的 bndbox 子节点表示的矩形框坐标进行水平翻转。在水平翻转过程中,函数首先获取矩形框的左右两个边界坐标 xmin 和 xmax,然后将 xmin 修改为原图像宽度减去 xmax,xmax 修改为原图像宽度减去 xmin,从而实现矩形框坐标的水平翻转。
最后,函数使用 ET.ElementTree.write 方法将修改后的 XML 标注文件保存到指定路径下。
需要注意的是,该函数的参数 image_width 是用于表示图像宽度的参数,它用于计算矩形框坐标的水平翻转。因此,在调用该函数时,需要将对应图像的宽度传入该参数中。

import os
import xml.etree.ElementTree as ET
from PIL import Image


# def flip_image_vertical(image_path, save_path, output_dir):
#     image = Image.open(image_path)
#     flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
#     save_dir = os.path.join(output_dir, os.path.relpath(os.path.dirname(image_path), os.path.dirname(input_image_dir)))
#     if not os.path.exists(save_dir):
#         os.makedirs(save_dir)
#     flipped_image.save(os.path.join(save_dir, os.path.basename(save_path)))
# 
# 
# def flip_bbox_vertical(xml_path, save_path, image_height, output_dir):
#     tree = ET.parse(xml_path)
#     root = tree.getroot()
#     for obj in root.iter('object'):
#         bbox = obj.find('bndbox')
#         ymin = int(bbox.find('ymin').text)
#         ymax = int(bbox.find('ymax').text)
#         bbox.find('ymin').text = str(image_height - ymax)
#         bbox.find('ymax').text = str(image_height - ymin)
#     save_dir = os.path.join(output_dir, os.path.relpath(os.path.dirname(xml_path), os.path.dirname(input_xml_dir)))
#     if not os.path.exists(save_dir):
#         os.makedirs(save_dir)
#     tree.write(os.path.join(save_dir, os.path.basename(save_path)))
# 
# 
# def main(input_image_dir, input_xml_dir, output_image_dir, output_xml_dir):
#     for root, dirs, files in os.walk(input_image_dir):
#         for file in files:
#             if file.endswith('.jpg'):
#                 # 竖直翻转图像
#                 image_path = os.path.join(root, file)
#                 flipped_image_path = os.path.join(os.path.relpath(root, input_image_dir),
#                                                   file.split('.')[0] + '_vertical_flipped.jpg')
#                 flip_image_vertical(image_path, flipped_image_path, output_image_dir)
# 
#                 # 修改XML文件中矩形框坐标
#                 xml_path = os.path.join(input_xml_dir, file.split('.')[0] + '.xml')
#                 flipped_xml_path = os.path.join(os.path.relpath(root, input_image_dir),
#                                                 file.split('.')[0] + '_vertical_flipped.xml')
#                 flip_bbox_vertical(xml_path, flipped_xml_path, Image.open(image_path).size[1], output_xml_dir)
# 
# 
# if __name__ == '__main__':
#     input_image_dir = 'img/image'
#     input_xml_dir = 'img/label'
#     output_image_dir = 'img_vertical_flip/image'
#     output_xml_dir = 'img_vertical_flip/label'
#     if not os.path.exists(output_image_dir):
#         os.makedirs(output_image_dir)
#     if not os.path.exists(output_xml_dir):
#         os.makedirs(output_xml_dir)
#     main(input_image_dir, input_xml_dir, output_image_dir, output_xml_dir)

def flip_image_horizontal(image_path, save_path):
    image = Image.open(image_path)
    flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)
    flipped_image.save(save_path)


def flip_bbox_horizontal(xml_path, save_path, image_width):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    for obj in root.iter('object'):
        bbox = obj.find('bndbox')
        xmin = int(bbox.find('xmin').text)
        xmax = int(bbox.find('xmax').text)
        bbox.find('xmin').text = str(image_width - xmax)
        bbox.find('xmax').text = str(image_width - xmin)
    tree.write(save_path)


def main(image_dir, xml_dir, output_dir):
    for root, dirs, files in os.walk(image_dir):
        for file in files:
            if file.endswith('.jpg'):
                # 水平翻转图像
                image_path = os.path.join(image_dir, file)
                flipped_image_path = os.path.join(output_dir, file.split('.')[0] + '_flipped.jpg')
                flip_image_horizontal(image_path, flipped_image_path)

                # 修改XML文件中矩形框坐标
                xml_path = os.path.join(xml_dir, file.split('.')[0] + '.xml')
                flipped_xml_path = os.path.join(output_dir, file.split('.')[0] + '_flipped.xml')
                flip_bbox_horizontal(xml_path, flipped_xml_path, Image.open(image_path).size[0])


if __name__ == '__main__':
    image_dir = 'img/image'
    xml_dir = 'img/label'
    output_dir = 'img_flip/output_dir'
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    main(image_dir, xml_dir, output_dir)

将目标所在区域裁剪出来

最后发现方法三好用!

方法一

将玻璃片所在区域裁剪出来。

# 日期:  2023/4/22 14:34
import cv2
import numpy as np

# 读取图片
img_path = r'D:\datasets\osr_original_img\100001.jpg'
img = cv2.imread(img_path)

# 灰度化处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 边缘检测
edges = cv2.Canny(gray, 100, 200)

# 轮廓检测
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 找到矩形轮廓
rect = None
for cnt in contours:
    approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
    if len(approx) == 4:
        rect = approx
        break

# 裁剪矩形区域
if rect is not None:
    rect = rect.reshape(-1, 2)
    x, y, w, h = cv2.boundingRect(rect)
    roi = img[y:y+h, x:x+w]
    cv2.imwrite('D:/your_cropped_image_path.jpg', roi)

代码中的步骤如下:

  1. 读取照片并转换为灰度图像。
  2. 对灰度图像进行边缘检测。
  3. 通过轮廓检测找到接近矩形的轮廓。
  4. 利用矩形轮廓的边界框(bounding box)裁剪出矩形区域。
  5. 将裁剪出的区域保存为新的图片。
    上述代码处理一些图片的时候会使输出全部为黑色。

方法二:

import cv2
import numpy as np

image = cv2.imread(r'D:\datasets\osr_original_img\100018.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=-1)

# subtract the y-gradient from the x-gradient
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)

# blur and threshold the image
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 90, 255, cv2.THRESH_BINARY)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# perform a series of erosions and dilations
closed = cv2.erode(closed, None, iterations=4)
closed = cv2.dilate(closed, None, iterations=4)

(cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

# compute the rotated bounding box of the largest contour
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))

# draw a bounding box arounded the detected barcode and display the image
# cv2.drawContours(image, [box], -1, (255, 255, 255), 2)
cv2.imshow("Image", image)
cv2.imwrite("contoursImage2.jpg", image)
cv2.waitKey(0)

Xs = [i[0] for i in box]
Ys = [i[1] for i in box]
x1 = min(Xs)
x2 = max(Xs)
y1 = min(Ys)
y2 = max(Ys)
hight = y2 - y1
width = x2 - x1
cropImg = image[y1:y1+hight, x1:x1+width]

cv2.imwrite('D:/your_warped_image_path18.jpg', cropImg)

参考

方法三

import matplotlib.pyplot as plt
import numpy as np
import cv2
import os
import math

# 图像灰度延展、直方图均衡化

file_root = "./osr_original_img"  # 当前文件夹下的所有图片
file_list = os.listdir(file_root)
save_out = "./crop_images/origin_imgs1"  # 保存图片的文件夹名称
for img_name in file_list:
    img_path = file_root + "/" + img_name

    original_image = cv2.imread(img_path, -1)
    image = original_image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (3, 3), 0)
    canny = cv2.Canny(blurred, 120, 255, 1)
    kernel = np.ones((9, 9), np.uint8)
    result = cv2.dilate(canny, kernel)
    # Find contours in the image
    cnts = cv2.findContours(result.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    # Obtain area for each contour
    contour_sizes = [(cv2.arcLength(contour, True), contour) for contour in cnts]

    # Find maximum contour and crop for ROI section
    if len(contour_sizes) > 0:
        largest_contour = max(contour_sizes, key=lambda x: x[0])[1]
        # cv2.drawContours(image, largest_contour, -1, (0, 255, 0), 10)
        x, y, w, h = cv2.boundingRect(largest_contour)
        # cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 5)
        ROI = original_image[y-100:y + h + 100, x-100:x + w + 100]

    out_name = img_name.split('.')[0]
    save_path = save_out + "/" + out_name + '.jpg'
    cv2.imwrite(save_path, ROI)

裁剪并纠偏

将玻璃片所在区域裁剪出来。并且把裁剪出来的图片纠偏,因为工业相机拍照的时候会产生畸变。

要将拍摄的图像进行纠偏,使矩形玻璃片在图像中成为矩形,可以使用OpenCV库中的透视变换(perspective transformation)来实现。

下面代码的问题是裁剪纠偏之后的图片相比于原图发生了旋转,像是经过了水平镜像,不知道是否对所有图片都是这样。

import cv2
import numpy as np

# 读取图片
img = cv2.imread(r'D:\datasets\osr_original_img\100002.jpg')

# 灰度化处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 边缘检测
edges = cv2.Canny(gray, 100, 200)

# 轮廓检测
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 找到矩形轮廓
rect = None
for cnt in contours:
    approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
    if len(approx) == 4:
        rect = approx
        break

# 纠偏图像
if rect is not None:
    rect = rect.reshape(-1, 2)
    rect = rect.astype(np.float32)
    (tl, tr, br, bl) = rect
    w1 = np.sqrt((tl[0]-tr[0])**2 + (tl[1]-tr[1])**2)
    w2 = np.sqrt((bl[0]-br[0])**2 + (bl[1]-br[1])**2)
    h1 = np.sqrt((tl[0]-bl[0])**2 + (tl[1]-bl[1])**2)
    h2 = np.sqrt((tr[0]-br[0])**2 + (tr[1]-br[1])**2)
    maxWidth = max(int(w1), int(w2))
    maxHeight = max(int(h1), int(h2))
    dst = np.array([[0, 0], [maxWidth-1, 0], [maxWidth-1, maxHeight-1], [0, maxHeight-1]], dtype=np.float32)
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
    cv2.imwrite('D:/your_warped_image_path2.jpg', warped)

代码中的步骤如下:

1.读取照片并转换为灰度图像。
2.对灰度图像进行边缘检测。
3.通过轮廓检测找到接近矩形的轮廓。
4.利用矩形轮廓的边界框裁剪出矩形区域。
5.计算矩形区域的四个顶点在变换后的图像中的位置。
6.利用透视变换(Perspective Transformation)将矩形区域变换为矩形。
7.将变换后的图像保存为新的图片。

在代码中,首先找到了接近矩形的轮廓,并通过轮廓的边界框计算了矩形区域的四个顶点在变换后的图像中的位置。然后,利用cv2.getPerspectiveTransform()函数求得透视变换矩阵M,并使用cv2.warpPerspective()函数将图像进行透视变换。变换后的图像将会是一个矩形,其中玻璃片也将成为一个矩形。

图像扩增方法合集(对单张图片)

注意修改读取和保存图片的路径,并根据需要修改其中的参数。

from PIL import Image, ImageEnhance, ImageFilter, ImageDraw
import random

img_path = 'crop_images/0427origin_imgs/100272.jpg'
num = 100272

image = Image.open(img_path)  # 打开图片文件


# 旋转30度

rotated_image = image.rotate(30)  # 将图片旋转30度
rotated_image.save("crop_images/rotated_image_{}.jpg".format(num))  # 保存旋转后的图片文件

# 水平翻转

flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)  # 将图片水平翻转
flipped_image.save("crop_images/flipped_image_{}.jpg".format(num))  # 保存翻转后的图片文件

# 随机裁剪

width, height = image.size  # 获取图片的宽和高
crop_width, crop_height = 500, 500  # 设定裁剪后的图片大小
left = random.randint(0, width - crop_width)  # 随机生成左上角横坐标
upper = random.randint(0, height - crop_height)  # 随机生成左上角纵坐标
right = left + crop_width  # 计算右下角横坐标
lower = upper + crop_height  # 计算右下角纵坐标
cropped_image = image.crop((left, upper, right, lower))  # 裁剪图片
cropped_image.save("crop_images/cropped_image_{}.jpg".format(num))  # 保存裁剪后的图片文件

# 平移

offset = (50, 50)  # 定义平移量
trans_image = image.transform(image.size, Image.AFFINE, (1, 0, offset[0], 0, 1, offset[1]))  # 对图片进行平移
trans_image.save("trans_image.jpg")  # 保存平移后的图片文件

# 对比度增强

contrast_enhancer = ImageEnhance.Contrast(image)  # 创建对比度增强器
enhanced_image = contrast_enhancer.enhance(1.5)  # 对图片进行对比度增强
enhanced_image.save("contrast_enhanced_image.jpg")  # 保存对比度增强后的图片文件

# 亮度增强

brightness_enhancer = ImageEnhance.Brightness(image)  # 创建亮度增强器
enhanced_image = brightness_enhancer.enhance(1.5)  # 对图片进行亮度增强
enhanced_image.save("brightness_enhanced_image.jpg")  # 保存亮度增强后的图片文件

# 颜色转换


converted_image = image.copy()  # 创建图片副本
r, g, b = converted_image.split()  # 分离图片的RGB通道
r = r.point(lambda i: i + 50)  # 对R通道进行颜色转换
g = g.point(lambda i: i - 30)  # 对G通道进行颜色转换
b = b.point(lambda i: i - 20)  # 对B通道进行颜色转换
converted_image = Image.merge("RGB", (r, g, b))  # 合并三个通道重构图片
converted_image.save("converted_image.jpg")  # 保存颜色转换后的图片文件

# 转换为灰度图

converted_image = image.convert("L")  # 将图片转换为灰度图
converted_image.save("gray_image.jpg")  # 保存灰度图

# 模糊

blurred_image = image.filter(ImageFilter.GaussianBlur(radius=2))  # 对图片进行高斯模糊
blurred_image.save("blurred_image.jpg")  # 保存模糊后的图片文件

# 锐化

sharpened_image = image.filter(ImageFilter.SHARPEN)  # 对图片进行锐化
sharpened_image.save("sharpened_image.jpg")  # 保存锐化后的图片文件

# 添加噪声

draw = ImageDraw.Draw(image)  # 创建绘制对象
width, height = image.size  # 获取图片的宽和高
for x in range(width):
    for y in range(height):
        draw.point((x, y), fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))  # 为每个像素点添加随机噪声
image.save("noisy_image.jpg")  # 保存添加噪声后的图片文件


文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户

相关推荐