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()
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<src_h and h>=0 and w<src_w 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()
图片缩放
在不考虑复用性的前提下,实验性的进行不插值缩放
#在该代码中由于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()
我们试着打印图像的分辨率,发现其为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()
从左至右分别为 均值插值 非线性差值 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()
上图为将其非线性插值放大,与原图的对比
对上面的代码进行整理,处理下边界条件实现的不插值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)
(512, 512, 3)
resize_lenna = cv2.resize(lenna,(64,64))
plt.axis("off")
plt.imshow(resize_lenna)
plt.show()
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()
图片旋转的实现
在下面的代码中使用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()
此处代码的缺陷有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()
仿射变换
垂直变换
将单个点的坐标(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()
水平变换
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()
python数字图像处理(一)图像的常见操作的更多相关文章
- 「转」python数字图像处理(18):高级形态学处理
python数字图像处理(18):高级形态学处理 形态学处理,除了最基本的膨胀.腐蚀.开/闭运算.黑/白帽处理外,还有一些更高级的运用,如凸包,连通区域标记,删除小块区域等. 1.凸包 凸包是指一 ...
- python数字图像处理(17):边缘与轮廓
在前面的python数字图像处理(10):图像简单滤波 中,我们已经讲解了很多算子用来检测边缘,其中用得最多的canny算子边缘检测. 本篇我们讲解一些其它方法来检测轮廓. 1.查找轮廓(find_c ...
- Win8 Metro(C#) 数字图像处理--1 图像打开,保存
原文:Win8 Metro(C#) 数字图像处理--1 图像打开,保存 作为本专栏的第一篇,必不可少的需要介绍一下图像的打开与保存,一便大家后面DEMO的制作. Win8Metro编程中,图像相关 ...
- python数字图像处理(1):环境安装与配置
一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...
- 初始----python数字图像处理--:环境安装与配置
一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...
- MATLAB数字图像处理(一)基础操作和傅立叶变换
数字图像处理是一门集计算机科学.光学.数学.物理学等多学科的综合科学.随着计算机科学的发展,数字图像处理技术取得了巨大的进展,呈现出强大的生命力,已经在多种领域取得了大量的应用,推动了社会的发展.其中 ...
- Win8 Metro(C#)数字图像处理--4图像颜色空间描述
原文:Win8 Metro(C#)数字图像处理--4图像颜色空间描述 图像颜色空间是图像颜色集合的数学表示,本小节将针对几种常见颜色空间做个简单介绍. /// <summary> / ...
- python数字图像处理(五) 图像的退化和复原
import cv2 import numpy as np import matplotlib.pyplot as plt import scipy import scipy.stats %matpl ...
- python数字图像处理(10):图像简单滤波
对图像进行滤波,可以有两种效果:一种是平滑滤波,用来抑制噪声:另一种是微分算子,可以用来检测边缘和特征提取. skimage库中通过filters模块进行滤波操作. 1.sobel算子 sobel算子 ...
随机推荐
- vue-如何输出Hello world
首先引入vue.js文件 <script src="vue.js"></script> <!DOCTYPE html> <html> ...
- HTML基础:用表单写一个简易登录页面
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- SpringBoot集成H2database
转载:https://blog.csdn.net/chenhao_c_h/article/details/80332260 h2database为我们提供了十分轻量,十分快捷方便的内嵌式数据库 H2是 ...
- CF 36E Two Paths
传送门 真实的自闭= =+ 考试的时候老师明明说了可以路径为空T^T 然后光荣的挂掉了 20分的链[明明是最送分的] 上来就看出来欧拉回路了嘛 然后思考了一下大概奇点配个对 删一条简单路径剩下的跑欧拉 ...
- python运行windows终端程序
其实是用python控制windows里的shell 1.windows有PowerShell,可以通过搜索打开,运行python不需要打开shell 2.用python里的subprocess函数, ...
- delphi 打开和关闭外部exe
一.打开外部exe 1.use文件-SHELLAPI 2.ShellExecute(handle,'open','E:\test.exe','-s','',SW_SHOWNORMAL); 二.关闭外部 ...
- mybatis源码分析之04Mapper接口的动态代理
在工作中,使用mybatis操作数据库,只需要提供一个接口类,定义一些方法,然后调用接口里面的方法就可以CRUD,感觉是牛了一逼! 该篇就是记录一下,mybatis是如何完成这波骚操作的,即分析我们测 ...
- Codeforces 814C - An impassioned circulation of affection
原题链接:http://codeforces.com/contest/814/problem/C 题意:有长度为n的一个字符串,q个询问,每个询问由数字m和字符c组成,问最多在字符串中替换m个字符,使 ...
- A Bug's Life - poj2492
Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status Descr ...
- [CSP-S模拟测试]:Revive(点分治)
题目背景 $Sparkling\ ashes\ drift\ along\ your\ flames \\ And\ softly\ merge\ into\ the\ sky$ 题目传送门(内部题1 ...