【PaddlePaddle学习笔记】从零开始学习图像分类01——图像处理入门基础

本系列文章链接

  1. 【PaddlePaddle学习笔记】从零开始学习图像分类01——图像处理入门基础
  2. 未完待续。。。。。。


一、关于图像的几个基本概念

1. 像素及其坐标

  像素是指在由一个数字序列表示的图像中的一个最小单位。

  通常情况下,以图像左上角为原点建立以像素为单位的直接坐标系u-v。像素的横坐标u与纵坐标v分别是在其图像数组中所在的列数与所在行数。(在OpenCV中u对应x,v对应y)

图片来源于网络

图片来源于网络

2. 图像的四种基本类型

(1)二值图

  二值图像是指:每个像素点均为黑色或者白色的图像。二值图像一般用来描述字符图像,其优点是占用空间少,缺点是,当表示人物,风景的图像时,二值图像只能展示其边缘信息,图像内部的纹理特征表现不明显。这时候要使用纹理特征更为丰富的灰度图像。

在这里插入图片描述

(2)灰度图

  灰度图,又称灰阶图。把白色与黑色之间按对数关系分为若干等级,称为灰度。灰度分为256阶。用灰度表示的图像称作灰度图。除了常见的卫星图像、航空照片外,许多地球物理观测数据也以灰度表示。

在这里插入图片描述

(3)索引图

  索引图像是一种把像素值直接作为RGB调色板下标的图像。索引图像可把像素值“直接映射”为调色板数值。一幅索引图包含一个数据矩阵data和一个调色板矩阵map,数据矩阵可以是uint8,uint16或双精度类型的,而调色板矩阵则总是一个m×3的双精度矩阵。调色板通常与索引图像存储在一起,装载图像时,调色板将和图像一同自动装载。

在这里插入图片描述

图片来源:百度百科

(4)彩色图

  彩色图形是指每个像素由R、G、B分量构成的图像,其中R、G、B是由不同的灰度级来描述的。

在这里插入图片描述

3. 分辨率

  分辨率 = 画面水平方向的像素值 * 画面垂直方向的像素值

(1)屏幕分辨率

  屏幕分辨率是屏幕图像的精密度,是指显示器所能显示的像素有多少。由于屏幕上的点、线和面都是由像素组成的,显示器可显示的像素越多,画面就越精细,同样的屏幕区域内能显示的信息也越多,所以分辨率是个非常重要的性能指标。可以把整个图像想象成是一个大型的棋盘,而分辨率的表示方式就是所有经线和纬线交叉点的数目。显示分辨率一定的情况下,显示屏越小图像越清晰,反之,显示屏大小固定时,显示分辨率越高图像越清晰。

(2)图像分辨率

  图像分辨率是指在计算机中保存和显示一幅数字图像所具有的分辨率,它和图像的像素有直接的关系。例如,一张分辨率为640×480像素的图片,其分辨率就达到了307200像素,也就是常说的30万像素;而一张分辨率为1600×1200的图片,它的像素就是200万。

4. 色彩空间

  “色彩空间”一词源于西方的“Color Space”,又称作“色域”,色彩学中,人们建立了多种色彩模型,以一维、二维、三维甚至四维空间坐标来表示某一色彩,这种坐标系统所能定义的色彩范围即色彩空间。我们经常用到的色彩空间主要有RGB、CMYK、Lab等。

5. 几种常见的图像格式

(1)JPEG

  联合照片专家组(外语简称:JPEG外语全称:Joint Photographic Expert Group),文件后辍名为".jpg"或".jpeg",是最常用的图像文件格式,由一个软件开发联合会组织制定,是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要的资料会被丢失,因此容易造成图像数据的损伤。

(2)PNG

  便携式网络图形(外语简称PNG、外语全称:Portable Network Graphics),是网上接受的最新图像文件格式。PNG能够提供长度比GIF小30%的无损压缩图像文件。它同时提供 24位和48位真彩色图像支持以及其他诸多技术性支持。由于PNG非常新,所以目前并不是所有的程序都可以用它来存储图像文件,但Photoshop可以处理PNG图像文件,也可以用PNG图像文件格式存储。

(3)GIF

  图形交换格式(外语简称:GIF、外语全称:Graphics Interchange Format),是CompuServe公司在 1987年开发的图像文件格式。GIF文件的数据,是一种基于LZW算法的连续色调的无损压缩格式。其压缩率一般在50%左右,它不属于任何应用程序。目前几乎所有相关软件都支持它,公共领域有大量的软件在使用GIF图像文件。

(4)PSD

  PhotoShopDocument(PSD)这是Photoshop图像处理软件的专用文件格式,文件扩展名是.psd,可以支持图层、通道、蒙板和不同色彩模式的各种图像特征,是一种非压缩的原始文件保存格式。扫描仪不能直接生成该种格式的文件。PSD文件有时容量会很大,但由于可以保留所有原始信息,在图像处理中对于尚未制作完成的图像,选用 PSD格式保存是最佳的选择。

(5)BMP

  位图(外语简称:BMP、外语全称:BitMaP)BMP是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。


二、基于OpenCV(Python)的图像操作

导入

import math
import random
import numpy as np
%matplotlib inline
import cv2
import matplotlib.pyplot as plt

1. 基本操作

(1) ROI

  ROI:Region of Interest.

截取ROI非常简单,指定图片的范围即可

# 创建一副图片
img = cv2.imread('cat.png')
# 转换颜色通道(改变顺序,由BGR变为RGB,使图片正常显示)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 截取猫脸ROI
face = img[0:740 , 400:1000]
plt.imshow(face)

运行结果如下:
在这里插入图片描述

(2)通道分割与合并

  彩色图的BGR三个通道是可以分开单独访问的,也可以将单独的三个通道合并成一副图像。分别使用 cv2.split()cv2.merge() :

# 创建一副图片
img = cv2.imread('lena.jpg')

# 通道分割
b, g, r = cv2.split(img)

# 通道合并
RGB_Image = cv2.merge([b,g,r])

RGB_Image = cv2.cvtColor(RGB_Image, cv2.COLOR_BGR2RGB)
plt.figure(figsize = (12,12))
#显示各通道信息
plt.subplot(141)
plt.imshow(RGB_Image,'gray')
plt.title('RGB_Image')

plt.subplot(142)
plt.imshow(r,'gray')
plt.title('R_Channel')

plt.subplot(143)
plt.imshow(g,'gray')
plt.title('G_Channel')

plt.subplot(144)
plt.imshow(b,'gray')
plt.title('B_Channel')

运行结果如下:
在这里插入图片描述

(3)色彩空间转换

常用的颜色空间转换如下:

  • RGB或BGR到灰度(COLOR_RGB2GRAY,COLOR_BGR2GRAY)
  • RGB或BGR到YcrCb(或YCC)(COLOR_RGB2YCrCb, COLOR_BGR2YCrCb)
  • RGB或BGR到HSV(COLOR_RGB2HSV,COLOR_BGR2HSV)
  • RGB或BGR到Luv(COLOR_RGB2Luv,COLOR_BGR2Luv)
  • 灰度到RGB或BGR(COLOR_GRAY2RGB,COLOR_GRAY2BGR)

使用举例:

img = cv2.imread('lena.jpg')

# 转换为灰度图
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 保存灰度图
cv2.imwrite('img_gray.jpg', img_gray)

(4)特定颜色物体追踪

  HSV是一个常用于颜色识别的模型,相比BGR更易区分颜色,转换模式用 COLOR_BGR2HSV 表示

在这里插入图片描述

图片来源于网络


下面以追踪蓝色为例:

# 加载一张有天空的图片
sky = cv2.imread('sky.jpg')

# 蓝色的范围,不同光照条件下不一样,可灵活调整
lower_blue = np.array([15, 60, 60])
upper_blue = np.array([130, 255, 255])

# 从BGR转换到HSV
hsv = cv2.cvtColor(sky, cv2.COLOR_BGR2HSV)

# inRange():介于lower/upper之间的为白色,其余黑色
mask = cv2.inRange(sky, lower_blue, upper_blue)

# 只保留原图中的蓝色部分
res = cv2.bitwise_and(sky, sky, mask=mask)

# 保存颜色分割结果
cv2.imwrite('res.jpg', res)

res = cv2.imread('res.jpg')
res = cv2.cvtColor(res, cv2.COLOR_BGR2RGB)
plt.imshow(res)

运行结果如下:
在这里插入图片描述
关于如何获取蓝色的HSV值的上下限lower和upper范围:

blue = np.uint8([[[255, 0, 0]]])
hsv_blue = cv2.cvtColor(blue, cv2.COLOR_BGR2HSV)
print(hsv_blue)

结果是[120, 255, 255]

2. 阈值分割

(1)固定阈值分割

import cv2
# 灰度图读入
img = cv2.imread('lena.jpg', 0)
# 颜色通道转换
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 阈值分割
ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
plt.imshow(th)

运行结果如下:
在这里插入图片描述

(2)自适应阈值

# 自适应阈值对比固定阈值
img = cv2.imread('lena.jpg', 0)

# 固定阈值
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值, ADAPTIVE_THRESH_MEAN_C:小区域内取均值
th2 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)
# 自适应阈值, ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
th3 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 17, 6)

titles = ['Original', 'Global(v = 127)', 'Adaptive Mean', 'Adaptive Gaussian']
images = [img, th1, th2, th3]
plt.figure(figsize=(12,12))
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])

运行结果如下:
在这里插入图片描述

3. 几何变换

导入

img = cv2.imread('cat.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

(1)缩放图片

# 按照指定的宽度、高度缩放图片
res = cv2.resize(img, (400, 500))
# 按照比例缩放,如x,y轴均放大一倍
res2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
plt.imshow(res)
plt.imshow(res2)

运行结果如下:
在这里插入图片描述
在这里插入图片描述

(2)翻转图片

dst = cv2.flip(img, 1)
plt.imshow(dst)

运行结果如下:
在这里插入图片描述

(3)平移图片

# 平移图片
import numpy as np
# 获得图片的高、宽
rows, cols = img.shape[:2]
# 定义平移矩阵,需要是numpy的float32类型
# x轴平移200,y轴平移500
M = np.float32([[1, 0, 100], [0, 1, 500]])
# 用仿射变换实现平移
dst = cv2.warpAffine(img, M, (cols, rows))
plt.imshow(dst)

在这里插入图片描述

4. 绘图功能

导入

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

(1)画线

# 画一条线宽为5的红色直线,参数2:起点,参数3:终点
cv2.line(img, (0, 0), (800, 512), (255, 0, 0), 5)
plt.imshow(img)

运行结果如下:
在这里插入图片描述

(2)画矩形

# 画一个矩形,左上角坐标(40, 40),右下角坐标(80, 80),框颜色为绿色
img = cv2.rectangle(img, (40, 40), (80, 80), (0, 255, 0),2) 
plt.imshow(img)

运行结果如下:
在这里插入图片描述

(3)添加文字

# 添加文字,加载字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 添加文字hello
cv2.putText(img, 'hello', (10, 200), font, 4, (255, 255, 255), 2, lineType=cv2.LINE_AA)
plt.imshow(img)

运行结果如下:
在这里插入图片描述

5. 图像运算

(1)图片相加

x = np.uint8([250])
y = np.uint8([10])
print(cv2.add(x, y))  # 250+10 = 260 => 255
print(x + y)  # 250+10 = 260 % 256 = 4

(2)图像混合

img1 = cv2.imread('lena.jpg')
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
img2 = cv2.imread('cat.png')
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)
img2 = cv2.resize(img2, (350, 350))
# 两张图片相加
res = cv2.addWeighted(img1, 0.6, img2, 0.4, 0)
plt.imshow(res)

运行结果如下:
在这里插入图片描述

(3)按位操作

img1 = cv2.imread('lena.jpg')
img2 = cv2.imread('logo.jpg')
img2 = cv2.resize(img2, (350, 350))
# 把logo放在左上角,所以我们只关心这一块区域
rows, cols = img2.shape[:2]
roi = img1[:rows, :cols]

# 创建掩膜
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

# 保留除logo外的背景
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
dst = cv2.add(img1_bg, img2)  # 进行融合
img1[:rows, :cols] = dst  # 融合后放在原图上
plt.imshow(dst)

运行结果如下:
在这里插入图片描述

6. 图像滤波

(1)均值滤波

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur = cv2.blur(img, (9, 9))  # 均值模糊
plt.imshow(blur)

运行结果如下:
在这里插入图片描述

(2)方框滤波

blur = cv2.boxFilter(img, -1, (9, 9), normalize=True)
plt.imshow(blur)

运行结果如下:
在这里插入图片描述

(3)高斯滤波

gaussian = cv2.GaussianBlur(img, (9, 9), 1)  # 高斯滤波
plt.imshow(gaussian)

运行结果如下:
在这里插入图片描述

(4)中值滤波

median = cv2.medianBlur(img, 9)  # 中值滤波
plt.imshow(median)

运行结果如下:
在这里插入图片描述

(5)双边滤波

blur = cv2.bilateralFilter(img, 9, 75, 75)  # 双边滤波
plt.imshow(blur)

运行结果如下:
在这里插入图片描述

(6)图像锐化

kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) #定义一个核
dst = cv2.filter2D(img, -1, kernel=kernel)
plt.imshow(dst)

运行结果如下:
在这里插入图片描述

7. 边缘检测

(1)Canny边缘检测

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
edges = cv2.Canny(img, 30, 70)  # canny边缘检测
plt.imshow(edges)

运行结果如下:
在这里插入图片描述

(2)先阈值分割后检测

_, thresh = cv2.threshold(img, 124, 255, cv2.THRESH_BINARY)
edges = cv2.Canny(thresh, 30, 70)
plt.imshow(edges)

在这里插入图片描述
运行结果如下:

8. 形态学操作

  形态学操作一般作用于二值化图,来连接相邻的元素或分离成独立的元素,腐蚀和膨胀是针对图片中的白色部分。

(1)腐蚀

  腐蚀的效果是把图片"变瘦",其原理是在原图的小区域内取局部最小值。因为是二值化图,只有0和255,所以小区域内有一个是0该像素点就为0。OpenCV中用 cv2.erode() 函数进行腐蚀,只需要指定核的大小就行:

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel)  # 腐蚀
plt.imshow(erosion)

运行结果如下:
在这里插入图片描述

  其中kernel可以是矩形/椭圆/十字形,可以用 cv2.getStructuringElement() 来生成不同形状的结构元素

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 矩形结构
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # 椭圆结构
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))  # 十字形结构

(2)膨胀

  膨胀与腐蚀相反,取的是局部最大值,效果是把图片"变胖":

dilation = cv2.dilate(img, kernel)  # 膨胀
plt.imshow(dilation)

运行结果如下:
在这里插入图片描述

(3)开/闭运算

类别开运算闭运算
操作先腐蚀后膨胀先膨胀后腐蚀
作用消除小区域填充小缝隙
实现cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

开运算:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 定义结构元素
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)  # 开运算
plt.imshow(opening)

运行结果如下:
在这里插入图片描述

闭运算:

closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)  # 闭运算
plt.imshow(closing)

运行结果如下:
在这里插入图片描述


三、PaddleClas数据增强代码解析与实战

导入

import cv2
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline

filename = 'huaji.jpg'
img = cv2.imread(filename)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)

运行结果如下:
在这里插入图片描述

1. 图片缩放

class Resize:
    def __init__(self, size):
        self.size = size

    def __call__(self, img):
        res = cv2.resize(img, self.size)
        return res

resize = Resize( (600, 600))
img2 = resize( img )
plt.imshow( img2 )

运行结果如下:
在这里插入图片描述

2. 图片翻转

class Flip:
    def __init__(self, mode):
        self.mode = mode

    def __call__(self, img):
       fliptemp = cv2.flip(img, self.mode)
       return fliptemp

flip = Flip( mode = 0 )
img2 = flip( img )
plt.imshow( img2 )

运行结果如下:
在这里插入图片描述

3. 图片旋转

class Rotate:
    def __init__(self, degree, size):
        self.degree = degree
        self.size = size

    def __call__(self, img):        
        rows, cols, channel = img.shape
        M = cv2.getRotationMatrix2D( (cols/2,rows/2), self.degree, self.size )
        dst = cv2.warpAffine(img, M, (rows,cols))
        return dst

rotate = Rotate( 45, 0.7)
img2 = rotate( img )
plt.imshow( img2 )

运行结果如下:
在这里插入图片描述

4. 图片亮度调节

class Brightness:
    def __init__(self, brightness_factor):
        self.brightness_factor = brightness_factor

    def __call__(self, img):
        imgtemp = img.copy()
        h, w, ch = imgtemp.shape
        for xi in range(0,w):
            for xj in range(0,h):
                imgtemp[xj,xi,0] = int(imgtemp[xj,xi,0] * self.brightness_factor)
                imgtemp[xj,xi,1] = int(imgtemp[xj,xi,1] * self.brightness_factor)
                imgtemp[xj,xi,2] = int(imgtemp[xj,xi,2] * self.brightness_factor)                
        return imgtemp

brightness = Brightness(0.6)
img2 = brightness(img)
plt.imshow(img2)

运行结果如下:
在这里插入图片描述

5. 图片随机剪裁

import random
import math

class RandomErasing(object):
    def __init__(self, EPSILON = 0.5, sl = 0.02, sh = 0.4, r1 = 0.3, mean = [0., 0., 0.]):
        self.EPSILON = EPSILON
        self.mean = mean
        self.sl = sl
        self.sh = sh
        self.r1 = r1

    def __call__(self, img):
        imgtemp = img.copy()
        if random.uniform(0, 1) > self.EPSILON:
            return imgtemp

        for attempt in range(100):
            area = imgtemp.shape[0] * imgtemp.shape[1]

            target_area = random.uniform(self.sl, self.sh) * area
            aspect_ratio = random.uniform(self.r1, 1 / self.r1)

            h = int(round(math.sqrt(target_area * aspect_ratio)))
            w = int(round(math.sqrt(target_area / aspect_ratio)))

            if w < imgtemp.shape[0] and h < imgtemp.shape[1]:
                x1 = random.randint(0, imgtemp.shape[1] - h)
                y1 = random.randint(0, imgtemp.shape[0] - w)
                if imgtemp.shape[2] == 3:
                    imgtemp[ x1:x1 + h, y1:y1 + w, 0] = self.mean[0]
                    imgtemp[ x1:x1 + h, y1:y1 + w, 1] = self.mean[1]
                    imgtemp[ x1:x1 + h, y1:y1 + w, 2] = self.mean[2]
                else:
                    imgtemp[x1:x1 + h, y1:y1 + w,0] = self.mean[0]
                return imgtemp

        return imgtemp


erase = RandomErasing()
img2 = erase(img)
plt.imshow(img2)  

运行结果如下:
在这里插入图片描述


四、参考资料

  1. https://aistudio.baidu.com/aistudio/education/group/info/11939
  2. https://baike.baidu.com/item/%E5%83%8F%E7%B4%A0/95084?fr=aladdin
  3. https://baike.baidu.com/item/%E4%BA%8C%E5%80%BC%E5%9B%BE%E5%83%8F
  4. https://baike.baidu.com/item/%E7%81%B0%E5%BA%A6%E5%9B%BE/8105733?fr=aladdin#1
  5. https://baike.baidu.com/item/%E7%B4%A2%E5%BC%95%E5%9B%BE%E5%83%8F/2954056?fr=aladdin
  6. https://baike.baidu.com/item/%E5%9B%BE%E5%83%8F%E6%A0%BC%E5%BC%8F/277878?fr=aladdin#1_11
  7. https://baike.baidu.com/item/%E5%83%8F%E7%B4%A0%E5%9D%90%E6%A0%87/5372225?fr=aladdin
  8. https://baike.baidu.com/item/%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4/4615427?fr=aladdin
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值