基于python-tensorflow的机器视觉学习手札 (1.2)图像处理篇-几何变换、邻域模板操作

1 图像的几何变换

1.1 平移

matlab里实现很简单,无非就是考虑平移后把溢出的部分剪切掉还是放大整个图像的大小来容纳整个图像而已。。
在python中,以cv2的方法为例:

import cv2
import numpy as np

img = cv2.imread('image.jpg',0)
rows,cols = img.shape

M = np.float32([[1,0,20],[0,1,20]])
dst = cv2.warpAffine(img,M,(cols,rows))

M是一个2*3的矩阵,表示对图像的各种处理,而cv2.warpAffine是综合的图像几何变换函数,功能随M的变换而改变。(有点像matlab中的imtransform,这个本小节后面会说)

1.2 镜像(反转)

镜像分为水平镜像和垂直镜像,像素点对应对称轴对面的相应像素,值做一个交换。这里给出一个matlab子函数实现镜像操作:

function output_image = (imput_image, n)
%参数n 代表镜像方式,1为水平,2为垂直,3为水平垂直
I = imput_image;
[M, N, G] = size(I);
J = I ;
if (n == 1)
    for i = 1:M
        for j = 1:N
            J(i, j, :) = I(M-i+1, j, :);
        end
    end
elseif (n == 2) 
    for i = 1:M
        for j = 1:N
            J(i, j, :) = I(i, N-j+1, :);
        end
    end
elseif (n == 3)
    for i = 1:M
        for j = 1:N
            J(i, j, :) = I(M-i+1, N-j+1, :);
        end
    end
else
    error('参数n输入错误,请查阅子函数备注')
end
output_image = J;

1.3 缩放

matlab中提供了imresize函数来实现缩放的功能,可以选择三种差值方式:最邻近差值,双线性差值,双三次差值。
在python-cv2中,也可以用resize来实现功能

import cv2
import numpy as np
img = cv2.imread('image.jpg')
res = cv2.resize(img,None,fx=0.5, fy=2, interpolation = cv2.INTER_CUBIC)

这里用的是双三次差值,此外还有最邻近,双线性(默认),重采样,Lanczos差值可以选择。
有关差值效率的问题,可以去百度,分析的还蛮多的。

1.4 转置(其实和反转差不多啦)

就是把坐标轴互换,实现转置。主要注意一下图像的大小会改变,创建新矩阵的时候注意就可以了。

1.5 旋转

同上,旋转后大小同样会改变。
在matlab中通常用imrotate来实现旋转一个角度。可以选择三种差值方式:最邻近差值,双线性差值,双三次差值。还可以选择对图像进行裁剪或放大以能容纳旋转后的图像。
而python中依然用warpAfform实现,代码如下:

import cv2
import numpy as np

img = cv2.imread('image.jpg',0)
rows,cols = img.shape

M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(img,M,(cols,rows))

这里的getRotationMatric2D是一个得到warpAffine中M矩阵的一个函数,与matlab中的maketform类似,但不同的函数对应不同的操作,又和matlab中有所区别。

1.6 剪切

这里matlab和opencv提供的python代码不太一样,matlab是真正的输出另一幅图像,而opencv除了可以输出,还可以先选区,再进行操作,然后解放选区,实现对图片中部分像素进行操作的功能。在应用过程中,python这种方法更为方便一些(其实自己写库/子函数两种都可以实现)。
matlab中提供了imcrop来实现剪切的功能,调用格式看上一篇留的百度网盘中的pdf,或者直接查看imcrop的m文件。(主要是懒得写)
python中选区的代码如下:

cv.SetImageROI(im, (50,50,150,150)) #Give the rectangle coordinate of the selected area

cv.ResetImageROI(im) # Reset the ROI

两个语句中插入对选取对象操作,直接输出就是剪切后的图像。

空间变换

仔细说一下,matlab中的imtransform函数。imtranform函数的功能随着parameter中的结构体改变,而结构体可以通过maketform函数得到。当然也可以自己写,有列表如下:
(不知道为啥插入图片插入不了)

放射性变换类型 a0 a1 a2 b0 b1 b2
平移 1 0 △x 0 1 △y
缩放 sx 0 0 0 sy 0
逆时针旋转α角 cosα sinα 0 -sinα cosα 0
水平切变 1 0 0 shx 1 0
垂直切变 1 shy 0 0 1 0
整体切变 1 shy 0 shx 1 0

第三行一般都是[0,0,1],这也就是python中的warpAffine中的M矩阵。这时matlab的图像处理模块与opencv终于联系到了一起!可喜可贺可喜可贺

2 图像的邻域、模板操作

邻域操作就是指输出图像的像素点取值取决于输入图像的某个点及其邻域内的像素取值,而模板操作可以说是我们平时常用的滤波器的本质。说着感觉好抽象(

2.1 图像的邻域操作

在matlab中,提供了几个邻域操作的函数,可以通过直接调用来实现各种操作,分别是 通用滑动邻域操作函数nlfilter、列方向邻域操作函数colfilt、分离邻域操作函数blockproc。 具体使用方法可以看函数自身的说明,简要介绍一下区别:
blockproc就是把图像分成一个一个的小方块,分别进行下一步操作,事先要提供函数句柄。例程如下:

clc; clear all ;close all;
Img_text = imread('image.jpg');
rotate90 = @(block_struct) imrotate (block_struct.data, 90);
I1 = blockproc (Img_text,[50,50],rotate90);
imshow(I1);

这个block结构体的变量名分别有data、border(说明块数据的垂直水平结构)、blockSize(说明块的尺寸)、imageSize(说明输入图像大小)、location(说明块数据第一像素的位置)。
nlfiltercolfilt 都是邻域操作函数,都多被用于滤波。
(后面matlab滤波器的区别这段部分,引用了一篇新浪博客的部分内容,特此鸣谢@流浪的大锤,原贴地址:http://blog.sina.com.cn/s/blog_bfb1429c0101kkzm.html ,未能联系上原作者,如有冒犯,请告知我,我会协商或删除)
先说明colfilt ,通常用法是:
img = colfilt(img,[m n],'block_type', @myfunction);
colfilt是matlab中邻域操作速度最快的一种,但它占有内存较大。
过程是:
1 读入img,得到img.rows*img.size矩阵;
2 对每个像素,取[m n]的邻域,对边界处,默认为0填充;(也可用replicate等填充)
3 对每个邻域像素,按列顺序遍历,展开成m*n为列向量;
4 调用im2col函数,将img.rows*img.size个列向量组合成(m*n)*(img.rows*img.size)的临时矩阵;
5 myfunction对整个临时矩阵的每一列操作,如myfunction为mean,则对临时矩阵的每一列算平均值,最后返回
1*(img.rows*img.size)的行向量;
6 调用col2im函数,将1*(img.rows*img.size)的行向量转化成img.rows*img.size的矩阵,得到结果。

另外:
colfilt步骤4中临时矩阵的列是动态的,故所有涉及到某一列的操作都出错,但是为什么这样设计呢?
(一个理解:matlab每次在临时矩阵中取随机列数的子矩阵,对其进行myfunction的操作)

实例:

% testing 对矩阵取邻域中中间位置的值,返回原矩阵;
 b= [1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5]

c=colfilt(b, [3 3], 'sliding', @myfilter);

function re = myfilter(A)

rows = size(A, 1);
rows = floor(rows/2 +1);
re = A(rows, :);

end

以上得到正确的结果。
关键:自定义函数返回的必须是1*(???)的行向量!

如果将:

rows = size(A, 1);
rows = floor(rows/2 +1);
re = A(rows, :);

改为:

[rows cols] = size(A);
rows = floor(rows*cols/2 +1);
re = A(rows, :);

结果出错:

Error in ==> colfilt at 149
        b = reshape(feval_r(fun,x,params{:}), size(a));

原因在于:cols是动态变化的!
而nlfilter不是对列操作,返回的是固定矩阵,过程为:
1 读入img,得到img.rows*img.size矩阵;
2 对每个像素,取[m n]的邻域,对边界处,默认为0填充;(也可用replicate等填充)
3 调用fun函数,传入参数为m*n矩阵,返回的是邻域中心的新值;
4 循环遍历整张图片所有像素,得到结果。
nlfilter定义较为简单,没有列局限性,但运行速度稍慢。

还有一个滤波函数imfilter,一并说了:
用法是
B = imfilter(A, H, option1, option2,...)
colfiltnlfilter主要用在非线性滤波中,imfilter则用在线性滤波中。
A:待处理的矩阵;
H:滤波模板,matlab中定义了很多现成的滤波模板;
option1:边界参数,定义怎样填充A的边界,replicate还是0或者是circular;
option2:输出参数,’same’表示输出矩阵和输入一样大;’full’输出矩阵和填充后矩阵一样大。
python中很多滤波都有自己的函数,函数名与功能相匹配。与imfilter类似,在python中用filter2D来作为卷积的工具(也是邻域操作的一种),卷积核(滤波模板)可以自己设定,一般用numpy中的array来设置。

2.2 图像的区域操作

在图像处理过程中,用户通常选择感兴趣的区域进行操作。
在matlab中,有几种方式来选择区域,分别是多边形区域选择函数roipoly、灰度ROI区域选择函数roicolor、区域填充函数roifill、区域滤波函数roifilt2。实质上都是通过选择区域,然后加一个掩膜,再对roi区域进行操作。
python中可以用numpy切片的方式来选择roi区域,也可以用绘制边缘,再填充作为掩膜来选择roi区域,比较灵活。
再次强调,这些都是个人的不成熟的学习过程中的想法与总结,如果有错误欢迎在评论区告知我,也欢迎同样的初学者或大佬进行讨论,跪谢!

猜你喜欢

转载自blog.csdn.net/dimei0938/article/details/81448655