1. 像素基本操作
1.1 读取、修改像素
可以通过[行,列]坐标来访问像素点数据,对于多通道数据,返回一个数组,包含所有通道的值,对于单通道数据(如gray),返回指定坐标的值,也可以通过 [行,列,通道index] 来访问某坐标某通道的值。
1
2
3
|
1
2
3
4
5
6
7
|
>>> px = img[ 100 , 100 ]
>>> print ( px )
[ 157 166 200 ]
# accessing only blue pixel
>>> blue = img[ 100 , 100 , 0 ]
>>> print ( blue )
157
|
可以直接通过坐标修改像素值
1
2
3
|
>>> img[ 100 , 100 ] = [ 255 , 255 , 255 ]
>>> print ( img[ 100 , 100 ] )
[ 255 255 255 ]
|
然而直接像上面这样去读取、修改每个像素的值,效率是比较低的,可以使用下面的方法,效率是更高的
1
2
3
4
5
6
7
|
# accessing red value
>>> img.item( 10 , 10 , 2 )
59
# modifying red value
>>> img.itemset(( 10 , 10 , 2 ), 100 )
>>> img.item( 10 , 10 , 2 )
100
|
1.2 读取图像属性
读取图像尺寸,返回一个元组 (行,列,通道数)
1
2
|
>>> print ( img.shape )
( 342 , 548 , 3 )
|
读取像素大小, 行 列 通道数
1
2
|
>>> print ( img.size )
562248
|
像素数据类型
1
2
|
>>> print ( img.dtype )
uint8
|
1.3 图像roi操作
可以直接编辑像素区域,例如把图像左下角50*50的像素复制到左上角
1
2
3
4
5
6
7
8
|
import cv2
import numpy as np
img = cv2.imread( "test.jpg" )
print (img.shape)
roitest = img[ 475 : 525 , 0 : 50 ]
img[ 0 : 50 , 0 : 50 ] = roitest
cv2.imshow( "image" ,img)
cv2.waitkey( 0 )
|
1.4 分割、合并通道
有些情况下需要对图像的某一通道数据进行操作,此时会用到分割、合并通道数据
1
2
|
>>> b,g,r = cv2.split(img)
>>> img = cv2.merge((b,g,r))
|
或者
1
|
b = img[:,:, 0 ]
|
假设想编辑红色通道的数据,全部设置为0,不需要这样分割后编辑, img[:,:,2] = 0
这样即可。cv2.split操作是一个很耗时的操作,可以用numpy索引替代的操作,尽量用numpy索引来做。
1.4 生成图像边框
使用 cv2.copymakeborder
函数可添加图像边框,支持多种边框算法
1
2
3
4
5
6
7
8
9
10
11
|
void cv::copymakeborder (
inputarray src, / / 原图
/ / 目标图(cpp版本中,若传入此数据且选border_transparent,则此数据被top / bottom / left / right切出来的roi部分不会被做任何修改,此图像大小 = dst.rows + top + bottom,dst.cols + left + right)
outputarray dst,
int top, / / top / left / bottom / right 四个方向上的边框像素
int bottom,
int left,
int right,
int bordertype, / / 边框类型见下图
const scalar & value = scalar() / / 边框类型为border_constant时的边框像素
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
blue = [ 255 , 0 , 0 ]
img1 = cv2.imread( "test.jpg" )
replicate = cv2.copymakeborder(img1, 100 , 100 , 100 , 100 , cv2.border_replicate)
reflect = cv2.copymakeborder(img1, 100 , 100 , 100 , 100 , cv2.border_reflect)
reflect101 = cv2.copymakeborder(img1, 100 , 100 , 100 , 100 , cv2.border_reflect_101)
wrap = cv2.copymakeborder(img1, 100 , 100 , 100 , 100 , cv2.border_wrap)
constant = cv2.copymakeborder(img1, 100 , 100 , 100 , 100 , cv2.border_constant, value = blue)
print (img1.shape, reflect.shape)
plt.subplot( 231 ), plt.imshow(img1, 'gray' ), plt.title( 'original' )
plt.subplot( 232 ), plt.imshow(replicate, 'gray' ), plt.title( 'replicate' )
plt.subplot( 233 ), plt.imshow(reflect, 'gray' ), plt.title( 'reflect' )
plt.subplot( 234 ), plt.imshow(reflect101, 'gray' ), plt.title( 'reflect_101' )
plt.subplot( 235 ), plt.imshow(wrap, 'gray' ), plt.title( 'wrap' )
plt.subplot( 236 ), plt.imshow(constant, 'gray' ), plt.title( 'constant' )
plt.show()
|
上面的例子可以比较直观的看到各种border的效果,同时也能发现,python版的api与cpp版本的相比,默认初始化了一块原始图尺寸+各方向边框尺寸的图像内存,作为内置的dst参数。
输出尺寸:(525, 700, 3) (725, 900, 3)
2. 图像的基本算术操作
2.1 图像相加
图像相加,两个图像应该有相同的shape,或者图像和一个标量相加,或者图像和一个与其通道数相同的一维数组相加。
opencv的相加与numpy相加时,在超出数据类型范围时的处理不同
1
2
3
4
5
6
|
>>> x = np.uint8([ 250 ])
>>> y = np.uint8([ 10 ])
>>> print ( cv2.add(x,y) ) # 250+10 = 260 => 255
[[ 255 ]]
>>> print ( x + y ) # 250+10 = 260 % 256 = 4
[ 4 ]
|
cpp版本的api还支持mask等参数
1
2
3
4
5
6
7
|
void cv::add (
inputarray src1,
inputarray src2,
outputarray dst,
inputarray mask = noarray(),
int dtype = - 1
)
|
2.2 图像混合
opencv通过 cv::addweighted
函数提供了将两个图像混合在一起的方法
dst=α⋅img1+β⋅img2+γ
1
2
3
4
5
6
|
img1 = cv2.imread( 'ml.png' )
img2 = cv2.imread( 'opencv-logo.png' )
dst = cv2.addweighted(img1, 0.7 ,img2, 0.3 , 0 )
cv2.imshow( 'dst' ,dst)
cv2.waitkey( 0 )
cv2.destroyallwindows()
|
通过cv2.seamlessclone函数还能做更精细的图像局部融合。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.zoucz.com/blog/2019/03/07/50ef43b0-40a5-11e9-9947-3d7b79f522a2/