python图像分析_python数字图像处理(一)图像的常见操作

首先导入必要的库,使用Opencv读入图像,避免复杂的图像解析,同时使用Opencv作为算法的对比,由于使用环境为jupyter使用matplotlib直接可视化

import cv2

import matplotlib.pyplot as plt

import numpy as np

%matplotlib inline

图片的存储

图片实质上就是一个矩阵,一个640*320的灰白图像其实就是一个(640,320)的矩阵,每个坐标点的值就代表该像素点的灰度。

通常我们使用0-256的值来表示灰度的深浅,在三通道图像中表达某个通道的深浅,256=16*16,一次当我们使用16进制来表达三通道图像某个像素点的颜色时通常写作#ffffab这种形式

图片平移

图片平移是最简单的操作了,直接使用坐标加减即可。

例如将一个图像向右平移10个像素点实质就是把所有的像素点的横坐标加上10,如(0,0)坐标就会变成(10,0)。

在下图的实现中不对图像进行resize,超出图像原本范围的全部舍弃。

#使用matplotlib来显示opencv读取的图像

dave = cv2.imread("dave.jpg")

dave = cv2.cvtColor(dave,cv2.COLOR_BGR2RGB)

plt.axis("off")

plt.imshow(dave)

plt.show()

0069Secoly1flj2oroomrj3076070gmw.jpg

def translate(src,translate_x,translate_y):

src_h,src_w = src.shape[:2]

dst = np.zeros(src.shape,dtype=np.uint8)

for row in range(src_h):

for col in range(src_w):

h = int(row-translate_y)

w = int(col-translate_x)

if h=0 and w=0:

dst[row][col] = src[h][w]

return dst

new_image = translate(dave,50,30)

plt.axis("off")

plt.imshow(new_image)

plt.show()

0069Secoly1flj2p45cx0j3076070js5.jpg

图片缩放

在不考虑复用性的前提下,实验性的进行不插值缩放

#在该代码中由于opencv读取默认为BGR将其转化为RGB图像

gss = cv2.imread("Green_Sea_Shell.png")

gss = cv2.cvtColor(gss,cv2.COLOR_BGR2RGB)

plt.axis("off")

plt.imshow(gss)

plt.show()

0069Secoly1flj2pedexxj3079070tad.jpg

我们试着打印图像的分辨率,发现其为160*160的三通道图像,然后开始我们的实验性缩放

print(gss.shape)

#此处使用uint8格式的数据类型,gss将其转化为uint16是考虑到超出255的范围会出错,在结束后将其转化为原先的uint8类型

new_image = np.zeros((80,80,3),dtype=np.uint8)

gss = gss.astype(np.uint16)

(160, 160, 3)

试着直接比较两种插值,简化边界条件直接取四邻域均值

> PS:此处这并非线性插值,只是取其领域均值看相比直接的缩放是否会减少其锯齿感

for i in range(80):

for j in range(80):

#取靠近的四个像素点颜色的均值

pixel_sum = gss[i*2+1][j*2]+gss[i*2-1][j*2]+gss[i][j*2+1]+gss[i][j*2-1]+gss[i*2][j*2]

new_image[i][j] = (pixel_sum)/5

plt.subplot(131)

plt.axis("off")

plt.title("Average")

plt.imshow(new_image)

for i in range(80):

for j in range(80):

new_image[i][j] = gss[i*2][j*2]

plt.subplot(132)

plt.axis("off")

plt.imshow(new_image)

plt.title("non_linear")

gss = gss.astype(np.uint8)

new_image = cv2.resize(gss,(80,80))

plt.subplot(133)

plt.title("opencv resize")

plt.axis("off")

plt.imshow(new_image)

plt.show()

0069Secoly1flj2plmz1ij30ac041jsp.jpg

从左至右分别为 均值插值 非线性差值 opencv实现的resize

可以看出opencv默认的差值与非线性插值的区别,非线性插值的锯齿感更为明显

new_image = np.zeros((320,320,3),dtype=np.uint8)

for i in range(320):

for j in range(320):

new_image[i][j] = gss[int(i/2)][int(j/2)]

plt.subplot(121)

plt.axis("off")

plt.title("non_linear")

plt.imshow(new_image)

plt.subplot(122)

plt.axis("off")

plt.title("origin")

plt.imshow(gss)

plt.show()

0069Secoly1flj2pxbppqj30ai05j0u3.jpg

上图为将其非线性插值放大,与原图的对比

对上面的代码进行整理,处理下边界条件实现的不插值resize

def resize(orign_image,shape):

src_height, src_width = orign_image.shape[:2]

scale_height, scale_width = shape

sw = src_width/scale_width

sh = src_height/scale_height

if len(orign_image.shape)<3:

scale_image = np.zeros(shape,dtype=np.uint8)

else:

scale_image = np.zeros((shape[0],shape[1],orign_image.shape[2]),dtype=np.uint8)

def ceil(length, bound):

if length>=bound:

return int(bound-1)

elif length<0:

return 0

else:

return int(length)

for i in range(scale_height):

for j in range(scale_width):

scale_image[i][j] = orign_image[ceil(i*sh,src_height)][ceil(j*sw,src_width)]

return scale_image

使用上面的代码可以实现不插值缩放,但是其复用性不强,将坐标变换单独抽离出来,实现下面的线性插值

def bilinear_interpolate(im, y, x):

x = np.asarray(x)

y = np.asarray(y)

x0 = np.floor(x).astype(int)

x1 = x0 + 1

y0 = np.floor(y).astype(int)

y1 = y0 + 1

x0 = np.clip(x0, 0, im.shape[1]-1);

x1 = np.clip(x1, 0, im.shape[1]-1);

y0 = np.clip(y0, 0, im.shape[0]-1);

y1 = np.clip(y1, 0, im.shape[0]-1);

Ia = im[ y0, x0 ]

Ib = im[ y1, x0 ]

Ic = im[ y0, x1 ]

Id = im[ y1, x1 ]

wa = (x1-x) * (y1-y)

wb = (x1-x) * (y-y0)

wc = (x-x0) * (y1-y)

wd = (x-x0) * (y-y0)

return wa*Ia + wb*Ib + wc*Ic + wd*Id

def bilinear_resize(src,dsize):

src_h,src_w = src.shape[:2]

fh = dsize[0]/src_h

fw = dsize[1]/src_w

if len(src.shape)>3:

dst = np.zeros(dsize,dtype=np.uint8)

else:

dst = np.zeros(dsize+src.shape[2:],dtype=np.uint8)

for row in range(dst.shape[0]):

for col in range(dst.shape[1]):

dst[row][col] = bilinear_interpolate(src,row/fh,col/fw)

return dst

使用著名的lenna图来作为两种插值方式的对比

lenna = cv2.imread("lena.jpg")

lenna = cv2.cvtColor(lenna,cv2.COLOR_BGR2RGB)

plt.imshow(lenna)

plt.axis("off")

plt.show()

print(lenna.shape)

0069Secoly1flj2q2oq2vj307a070gog.jpg

(512, 512, 3)

resize_lenna = cv2.resize(lenna,(64,64))

plt.axis("off")

plt.imshow(resize_lenna)

plt.show()

0069Secoly1flj2qb6gmrj3072070dg0.jpg

nearst_lenna = resize(lenna,(512,512))

plt.subplot(121)

plt.axis("off")

plt.imshow(nearst_lenna)

bilinear_lenna = bilinear_resize(lenna,(512,512))

plt.subplot(122)

plt.axis("off")

plt.imshow(bilinear_lenna)

plt.show()

0069Secoly1flj2qh4piej30ai057jsq.jpg

图片旋转的实现

在下面的代码中使用numpy进行矩阵操作完成了图片的旋转

首先简单的使用书上的旋转矩阵将原坐标映射到新的坐标上

def rotate_image(src,rotate_angel):

src_h, src_w = src.shape[:2]

dsize = src.shape

dst = np.zeros(src.shape,dtype=np.uint8)

def _rotate_coodinate(x,y,angel):

import math

angel = angel/180*math.pi

coodinate = np.array([x,y,1])

rotate_matrix = np.array([[math.cos(angel),math.sin(angel),1],[-math.sin(angel),math.cos(angel),1],[0,0,1]])

coodinate = coodinate.dot(rotate_matrix)

x,y,_ = coodinate

return int(x),int(y)

for row in range(src_h):

for col in range(src_w):

dst_x,dst_y = _rotate_coodinate(col,row,rotate_angel)

if dst_x < 0 or dst_x >= src_w or dst_y<0 or dst_y>=src_h:

pass

else:

dst[dst_y][dst_x] = src[row][col]

return dst

new_image = rotate_image(lenna,-40)

plt.axis("off")

plt.imshow(new_image)

plt.show()

0069Secoly1flj2qrb2j5j307a070wg3.jpg

此处代码的缺陷有2点:

* 图片偏离中心

* 未反向映射导致,float转int时图像存在黑点

对上述代码进行修改,进行反向映射.

使用矩阵将其移动回中心,同时旋转矩阵为之前的逆

def rotate_image(src,rotate_angel):

src_h, src_w = src.shape[:2]

dsize = src.shape

dst = np.zeros(src.shape,dtype=np.uint8)

def _rotate_coodinate(x,y,angel):

import math

angel = angel/180*math.pi

coodinate = np.array([x,y,1])

rotate_matrix = np.array([[math.cos(angel),-math.sin(angel),0],[math.sin(angel),math.cos(angel),0],[0,0,1]])

rotate_center_first = np.array([[1,0,0],[0,-1,0],[-0.5*dsize[1],0.5*dsize[0],1]])

rotate_center_last = np.array([[1,0,0],[0,-1,0],[0.5*dsize[1],0.5*dsize[0],1]])

coodinate = coodinate.dot(rotate_center_first).dot(rotate_matrix).dot(rotate_center_last)

x,y,_ = coodinate

return int(x),int(y)

for row in range(src_h):

for col in range(src_w):

dst_x,dst_y = _rotate_coodinate(col,row,rotate_angel)

if dst_x < 0 or dst_x >= src_w or dst_y<0 or dst_y>=src_h:

pass

else:

dst[row][col] = src[dst_x][dst_y]

return dst

new_image = rotate_image(lenna,-40)

plt.imshow(new_image)

plt.axis("off")

plt.show()

0069Secoly1flj2r0i67tj307a070tb4.jpg

仿射变换

垂直变换

将单个点的坐标(x,y)转换为下面矩阵

\[\begin{bmatrix}

x & y & 1\end{bmatrix}

\]

乘上下面矩阵进行垂直方向的偏移变换

\[\begin{bmatrix}

1 & 0 & 0\\ s_v & 1 & 0\\ 0 & 0 & 1 \end {bmatrix}

\]

def transform(src,s_v):

src_h, src_w = src.shape[:2]

dsize = src.shape

dst = np.zeros(src.shape,dtype=np.uint8)

def _vertical_transform(x,y,s_v):

coodinate = np.array([x,y,1])

transform_matrix = np.array([[1,0,0],[s_v,1,0],[0,0,1]])

x,y,_ = coodinate.dot(transform_matrix)

if x>=dsize[1]:

x = dsize[1]-1

if x<0:

x = 0

if y>=dsize[0]:

y = dsize[0]-1

if y<0:

y = 0

return int(x),int(y)

for row in range(dst.shape[0]):

for col in range(dst.shape[1]):

dst_x,dst_y = _vertical_transform(col,row,s_v)

dst[dst_y][dst_x] = src[row][col]

return dst

new_image = transform(lenna,0.5)

plt.imshow(new_image)

plt.axis("off")

plt.show()

0069Secoly1flj2rcqe2cj307a070ac9.jpg

水平变换

def transform(src,s_h):

src_h, src_w = src.shape[:2]

dsize = src.shape

dst = np.zeros(src.shape,dtype=np.uint8)

def _vertical_transform(x,y,s_v):

coodinate = np.array([x,y,1])

transform_matrix = np.array([[1,s_h,0],[0,1,0],[0,0,1]])

x,y,_ = coodinate.dot(transform_matrix)

if x>=dsize[1]:

x = dsize[1]-1

if x<0:

x = 0

if y>=dsize[0]:

y = dsize[0]-1

if y<0:

y = 0

return int(x),int(y)

for row in range(dst.shape[0]):

for col in range(dst.shape[1]):

dst_x,dst_y = _vertical_transform(col,row,s_h)

dst[dst_y][dst_x] = src[row][col]

return dst

new_image = transform(lenna,0.3)

plt.imshow(new_image)

plt.axis("off")

plt.show()

0069Secoly1flj2rjl2xej307a07076p.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值