本篇文章附有opencv的基本函数使用和基本操作代码
导入库
-*- coding: utf-8 -*-
import cv2 #opencv2库
import numpy as np #numpy库
import matplotlib.pyplot as plt #类似于matlab工具
读入图像
函数为:cv2.imread(文件名[,显示控制参数])
返回值:一个图像
功能:读取图像
当显示控制参数为
1/cv2.IMREAD_UNCHANGED 不改变
0/cv2.IMREAD_GRAYSCALE 图像灰度
-1/cv2.IMREAD_COLOR 图像彩度
```
o=cv2.imread('C:\\Users\\Pandamin\\Desktop\\image\\1.jpg',0)
保存图像
函数为:cv2.imwrite(文件地址,文件名)
返回值:无
功能:保存图像
访问像素
函数为:img[位置[,通道数]]
返回值:该位置的像素
功能:得到该位置的图像,也可以更改其值
使用numpy访问像素
函数为:img.itemset((位置[,通道数]),设置像素值)
返回值:该位置的像素
功能:得到该位置的图像,也可以更改其值
获取图像属性
函数为:cv2.shape
返回值:返回行数,列数[,通道数]
功能:略
函数为:cv2.size
返回值:返回行数*列数[*通道数]
功能:略
函数为:cv2.dtype
返回值:返回图像的数据类型(unit8)
功能:略
感兴趣区域(截取图像img中200:400到200:400的像素)
函数为:face=img[200:400,200:400]
返回值:截取后的图像
功能:略
通道拆分和合并
函数为:b,g,r=cv2.split(图像名)
返回值:该图像b,g,r三个通道值
功能:获取三个通道的值
函数为:m=cv2.merge([b,g,r])
返回值:三个通道合成后的图像
功能:略
图像加法
函数为:cv2.add(a,b)
返回值:是将a,b图像的对应像素点%255得到加法之后的图像
功能:略
图像融合
函数为:cv2.addWeighted(图像1,图像1的系数,图像2,图像2的系数,亮度调节值)
返回值:融合后的图像
功能:可以将将两个残缺图像(且残缺的位置不同),融合为一个完整图像
类型转换
函数为:cv2.cvtColor(图像名,cv2.COLOR_BGR2RGB)
返回值:由BGR通道转化到RGB通道的图像
功能:略
函数为:cv2.cvtColor(图像名,cv2.COLOR_GRAY2BGR)
返回值:由灰度类型转化到BGR通道的图像
图像缩放
函数为:cv2.resize(src[,dsize=None],fx,fy)
返回值:缩放后的图像
参数:dsize缩放大小(列,行),如果dsize=None,则可以通过fx(水平),fy(垂直)去缩放
功能:略
图像旋转
函数为:cv2.flip(src,flipCode)
返回值:旋转后的图像
flipCode>0 返回以Y轴为对称旋转
flipCode=0 返回以x轴为对称旋转
flipCode<0 返回以x,y轴同时翻转
阈值分割
二进制阈值化
函数为:threshold(src,阈值,二值阈值化的最大值,cv2.THRESH_BINARY)
返回值:有两个,一个是阈值,一个是处理之后的结果。
功能:把图像中亮的处理为白色,暗的处理为黑色。
反二进制阈值化
函数为:threshold(src,阈值,二值阈值化的最大值,cv2.THRESH_BINARY_INV)
返回值:有两个,一个是阈值,一个是处理之后的结果。
功能:把图像中亮的处理为黑色,暗的处理为白色。
截断阈值化
函数为:threshold(src,阈值,二值阈值化的最大值,cv2.THRESH_TRUNC)
返回值:有两个,一个是阈值,一个是处理之后的结果。
功能:把图像中亮的处理为阈值,暗的处理为不变。
反阈值化为0
函数为:threshold(src,阈值,二值阈值化的最大值,cv2.THRESH_TOZERO_INV)
返回值:有两个,一个是阈值,一个是处理之后的结果。
功能:把图像中亮的处理为黑色0,暗的处理为不变。
阈值化为0
函数为:threshold(src,阈值,二值阈值化的最大值,cv2.THRESH_TOZERO)
返回值:有两个,一个是阈值,一个是处理之后的结果。
功能:把图像中亮的处理为不变,暗的处理为黑色。
均值滤波
函数为:cv2.blur(src,核大小)
返回值:返回均值化后的图像(图像更加平滑)
参数:核大小是以宽度&高度形式表示的元组
功能:使图像更加平滑
方框滤波
函数为:cv2.boxFilter(src,目标图像深度,核大小[,normalize属性=1])
返回值:处理后的图像
参数:
目标图像深度为int类型的目标图像深度,通常使用“-1”表示与原始图像一致
核大小:(n,n)表示有n列n行
normalize=true时,进行归一化处理,与均值滤波相同
normalize=false时,很容易溢出,像素值易大于255,得到白色的图像
高斯滤波
函数为:GaussianBlur(src,ksize,sigmaX)
返回值:略
参数:
ksize:为核大小(n,n),必须为奇数
sigmaX:X方向方差,控制权重,一般sigmaX=0,其会自动算一个方差
中值滤波
函数为:cv2.medianBlur(src,ksize)
参数:
ksize:必须为比1大的奇数且只要写一个数值n,不要写(n,n)
图像腐蚀
函数为:cv2.erode(src,kernel[,iterations=1])
参数:
kernel为卷积核,np.ones((n,n),np.unit8),
通过numpy的ones函数生成n*n的数值,其类型为unit8的卷积核
iterations为迭代次数
图像膨胀
函数为:cv2.dilate(src,kernel[,iterations=1])
参数:
kernel为卷积核,np.ones((n,n),np.unit8),
通过numpy的ones函数生成n*n的数值,其类型为unit8的卷积核
iterations为迭代次数
开运算:先进行腐蚀操作+膨胀操作,其作用去除噪声并保持原有的形状
函数为:cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
参数:
cv2.MORPH_OPEN 开运算
kernel 卷积核
闭运算:先进行膨胀+腐蚀操作,其作用去掉物体内的小黑点
函数为:cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
morphologyEx是形态学的一组函数,根据参数不同实现不同操作
参数:
cv2.MORPH_CLOSE 闭运算
kernel 卷积核
梯度运算:将一个图像分别进行膨胀,腐蚀操作并将其相减,得到轮廓信息
函数为:cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
morphologyEx是形态学的一组函数,根据参数不同实现不同操作
参数:
cv2.MORPH_GRADIENT 梯度运算
kernel 卷积核
礼帽(顶帽)运算:礼帽图像=原图像-开运算图像(去除噪声),得到噪声图像
函数为:cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
morphologyEx是形态学的一组函数,根据参数不同实现不同操作
参数:
cv2.MORPH_TOPHAT 礼帽运算
kernel 卷积核
黑帽图像处理:黑帽图像=闭运算图像-元素图像,得到图像内部的小黑点
函数为:cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
morphologyEx是形态学的一组函数,根据参数不同实现不同操作
参数:
cv2.MORPH_BLACKHAT 黑帽运算
kernel 卷积核
计算图像梯度,寻找边界(左右像素值差=0不是边界,!=0为边界,对其结果取绝对值)
sobel算子:|左-右|+|下-上|
函数为:cv2.Sobel(src,dddpth,dx,dy,[ksize])
参数:
dddpth:处理结果图像深度,通常情况下,可以设置为-1,表示与原图像的深度一致。
但是在计算的时候可能会出现负值,会发生信息丢失,所以需要更高的数据类型
即dddpth取cv2.CV_64F,取绝对值后,再转换为np.unit8类型
取绝对值通过cv2.convertScaleAbs(scr[,alpha[,beta]])
其作用是将原始图像转化为256色位图
dx:计算x方向的边界[dx=1,dy=0]
dy:计算y方向的边界[dx=0,dy=1]
通过函数cv2.addWeighted(sobel_dx,图像1的系数,sobel_dy,图像2的系数,亮度调节值)
ksize=-1时,等价于Scharr算子
scharr算子:|左-右|+|下-上|
函数为:cv2.Scharr(src,cv2.CV_64F,dx,dy)
dx:计算x方向的边界dx=Scharrx(src,ddpeth,dx=1,dy=0)
dy:计算y方向的边界dy=Scharry(src,ddpeth,dx=0,dy=1)
通过函数cv2.addWeighted(dx,图像1的系数,dy,图像2的系数,亮度调节值)
##且要满足dx>=0&&dy>=0&&&dx+dy==1
参数值:略
拉普拉斯算子:|左-右|+|左-右|+|下-上|+|下-上|
函数为:cv2.Laplacian(src,dddpth)
即dddpth取cv2.CV_64F,取绝对值后,再转换为np.unit8类型
取绝对值通过cv2.convertScaleAbs(scr[,alpha[,beta]])
其作用是将原始图像转化为256色位图
参数值:略
canny边缘检测
函数为:cv2.Canny(src,阈值1,阈值2)
参数值:阈值1minVal,阈值2maxVal,两个阈值是来控制边界信息的丰富程度的,
阈值越小得到图像的边界越丰富,越细致
图像金字塔
pyrDown(图像向下取样,变成原来的1/4),pyrUp(图像向下取样,变成原来4倍)
函数为:cv2.pyrDown(src) cv2.pyrUp(src)
参数值:略
取样可逆性研究:经过放到缩小图像是否不变?不一样,图像的清晰度变差
拉普拉斯金字塔
函数为:Li=Gi-PyrUp(PyrDown(Gi))
参数值:Gi原始图像,Li拉普拉斯图像
例如: od=cv2.pyrDown(o)
odu=cv2.pyrUp(od)
lapPyr=o-odu 拉普拉斯金字塔图像第0层
o1=od
o1d=cv2.pyrDown(o1)
o1du=cv2.pyrUp(o1d)
lapPyr1=o1-o1du 拉普拉斯金字塔图像第1层
即拉普拉斯图像+向下取样图像=原始图像
计算轮廓的面积
函数为:cv2.contourArea(cnt, True)
参数值:cnt为输入的单个轮廓值
计算轮廓的周长
函数为:cv2.arcLength(cnt, True)
参数值:cnt为输入的单个轮廓值
用于获得轮廓的近似值,使用cv2.drawCountors进行画图操作
函数为:cv2.aprroxPolyDP(cnt, epsilon, True)
参数值:cnt为输入的轮廓值, epsilon为阈值T,通常使用轮廓的周长作为阈值,True表示的是轮廓是闭合的
获得外接矩形
函数为:x, y, w, h = cv2.boudingrect(cnt)
参数值:x,y, w, h 分别表示外接矩形的x轴和y轴的坐标,以及矩形的宽和高, cnt表示输入的轮廓值
生成最小外接矩形
函数为:cv2.minAreaRect(cnt)
参数为:cnt为输入的轮廓值。[是点集数组或向量(里面存放的是点的坐标),并且这个点集中的元素不定个数。]
返回值:返回一个Box2D结构rect:(rect[0]中心(x,y), (rect[1][0]宽,rect[1][1]高),rect[2]旋转角度)
根据坐标在图像上画出矩形
函数为:cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
参数值: img表示传入的图片, (x, y)表示左上角的位置, (x+w, y+h)表示加上右下角的位置,(0, 255, 0)表示颜色,2表示线条的粗细
获得外接圆的位置信息
函数为:(x, y), radius = cv2.minEnclosingCircle(cnt)
参数值: (x, y)表示外接圆的圆心,radius表示外接圆的半径, cnt表示输入的轮廓
根据坐标在图上画出圆
函数为:cv2.Cricle(img, center, radius, (0, 255, 0), 2)
参数值:img表示需要画的图片,center表示圆的中心点,radius表示圆的半径, (0, 255, 0)表示颜色, 2表示线条的粗细
查找检测物体的轮廓
函数为:cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
参数值:
第一个参数是寻找轮廓的图像;二值图像
第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
cv2.RETR_EXTERNAL表示只检测外轮廓
cv2.RETR_LIST检测的轮廓不建立等级关系
cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE建立一个等级树结构的轮廓。
第三个参数method为轮廓的近似办法
cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
返回值:
一个是轮廓本身,还有一个是每条轮廓对应的属性,
可返回一个可选的hiararchy结果。[这是一个ndarray,其中的元素个数和轮廓个数相同;
每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3];
分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数]
(返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示)
图像轮廓:边界与轮廓的区别,轮廓是指连续的边界
函数为:cv2.drawContours(src,contours,contourldx,color[,thickness])
参数值:
contours:需要绘制的边缘数组
contourldx:需要绘制的边缘索引,如果全部绘制为-1
color:绘制的颜色,为BGR格式的Scalar
thinckness:绘制的密度,即轮廓画笔的粗细
绘制直方图
函数为:plt.hist(src.ravel(),256)
参数值:将src转化为一维数组 像素级一般为256,为八位的图像的灰度级:[0,255]
使用Opencv统计直方图
函数为:hist=cv2.calcHist(images,channels,mask,histSize,ranges[,accumulate])
通过函数plt.plot(hist,color='g/b/r')绘制出来
参数值:
images:原始图像
channels:指定通道
mask:掩码图像,统计整幅图像的直方图为None
histSize:BINS的数量,一般为[256]--灰度图像
ranges:像素值范围RANGE,一般为[0,255]
accumulate:累计标识
返回值:返回一个直方图hist
使用掩码直方图:先通过zeros生成全黑图像,在截取相应区域为白色
函数为:mask=np.zeros(src.shape,np.unit8)
mask[200:400,200:400]=255
参数值:src.shape元素图像的大小,np.unit8为八位的位图
返回值:略
直方图均值化原理:色彩的细节更加丰富
函数为:equ=cv2.qualizeHist(src)
参数值:略
返回值:略
subplot函数:一个窗口显示多个图像
函数为:plt.subplot(n行,n列,窗口序列)
例如:plt.subplot(121),plt.hist(img.ravel(),256)
plt.subplot(122),plt.hist(img.ravel(),256)
函数为:imshow(x,cmap=None)
参数值:x为需要绘制的图像
cmap为颜色图谱,默认为RGB(A)颜色空间
若要显示灰度图像:cmap=plt.cm,gray
若雅显示彩色图像:如果是通过python读进来的,则不需要处理RGB
如果是通过opencv读进来的,则其默认BGR,要调整色彩空间
使用默认值,显示彩色图像
plt.subplot(221)
plt.imshow(scr_color),plt.axis('off')
使用gray参数,显示彩色图像
plt.subplot(222)
plt.imshow(src_color,cmap=plt.cm.gray),plt.axis('off')
使用默认值,显示彩色度图像
plt.subplot(223)
plt.imshow(src_gray),plt.axis('off')
使用gray参数,显示灰度图像【灰度图像+灰度类型才可以显示灰度图像】
plt.subplot(224)
plt.imshow(src_gray,cmap=plt.cm.gray),plt.axis('off')#设置直方图没有坐标
傅里叶变换
函数为:f=np.fft.fft2(src)
返回值:返回一个复数的数组
移动到中心位置:将零频率分量移动到频谱中心
函数为:fshift=np.fft.fftshift(f)
将复数数组转化为灰度图像-->20*np.log(np.abs(fshift))设置频谱的范围
逆傅里叶变换
函数为:ifshift=np.fft.ifftshift(f)
iimg=np.fft.ifft2(ishift)
iimg=np.abs(iimg)
显示图像,删除所有窗口
函数为:cv2.imshow(窗口名,图像名)
cv2.waitKey([,delay])
cv2.destroyAllWindows()
参数值:
delay:
delay>0 等待delay毫秒
delay<0 等待键盘单击
delay=0 无限等待
参考代码一
# -*- coding: utf-8 -*-
import cv2 #opencv2库
import numpy as np
import time
#读取图片
o=cv2.imread('C:/Users/Pandamin/Desktop/img/1.jpg',1)
#o1=cv2.imread('C:/Users/Pandamin/Desktop/img/1.jpg',0)
#cv2.imshow('src',o)
#cv2.imshow('src1',o1)
'''
frameWidth=o[0]
frameHeight=o[1]
frameChannels=o[2]
frameArray=np.frombuffer(o[6],dtype=np.unit8).reshape([frameHeight,frameWidth,frameChannels])
'''
#转化成HSV
hue_image = cv2.cvtColor(o, cv2.COLOR_BGR2HSV)
#cv2.imshow('hue_image', hue_image)
#双阈值化处理
low_range = np.array([160, 83, 100])
high_range = np.array([180, 255, 255])
#OpenCV中的inRange()函数可实现二值化功能(这点类似threshold()函数)
#更关键的是可以同时针对多通道进行操作,使用起来非常方便!
#将两阈值范围内的设置为白色,不在的设置为黑色,具有双阈值化操作
th = cv2.inRange(hue_image, low_range, high_range)
#cv2.imshow('HSV_hueimgae', th)
#th = cv2.inRange(o, low_range, high_range)
#cv2.imshow('HSV_o', th)
#二进制阈值化处理(只能够将大于阈值的显示白色,小于阈值的显示黑色,前提是灰度图像)
#r,b=cv2.threshold(hue_image,127,255,cv2.THRESH_BINARY)
#cv2.imshow('threshold_hue', b)
r,b=cv2.threshold(th,127,255,cv2.THRESH_BINARY)
cv2.imshow('threshold_o', b)
# 平滑处理
gaus=cv2.GaussianBlur(th,(7,7),1.5)
#cv2.imshow('result', gaus)
'''
# 腐蚀
eroded = cv2.erode(gaus, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (4, 4)), iterations=2)
cv2.imshow('result腐蚀', eroded)
# 膨胀
dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=2)
cv2.imshow('result膨胀', dilated)
'''
#开运算
kernel=np.ones((5,5))
openA=cv2.morphologyEx(gaus,cv2.MORPH_OPEN,kernel)
cv2.imshow('open', openA)
#梯度运算
openA=cv2.Canny(openA,30,100)
cv2.imshow('open1', openA)
# Hough Circle
'''
cv2.HoughCircles(image,method,dp,minDist[, circles[,param1, param2[,minRadius[,maxRadius]]]]])
image 不用多说,输入矩阵
method cv2.HOUGH_GRADIENT 也就是霍夫圆检测,梯度法
dp 计数器的分辨率图像像素分辨率与参数空间分辨率的比值
(官方文档上写的是图像分辨率与累加器分辨率的比值,它把参数空间认为是一个累加器,毕竟里面存储的都是经过的像素点的数量),dp=1,则参数空间与图像像素空间(分辨率)一样大,dp=2,参数空间的分辨率只有像素空间的一半大
minDist 圆心之间最小距离,如果距离太小,会产生很多相交的圆,如果距离太大,则会漏掉正确的圆
param1 canny检测的双阈值中的高阈值,低阈值是它的一半
param2 最小投票数(基于圆心的投票数)
minRadius 需要检测圆的最小半径
maxRadius 需要检测圆的最大半径
'''
circles = cv2.HoughCircles(openA, cv2.HOUGH_GRADIENT, 1, 60, param1=15, param2=7, minRadius=5, maxRadius=50)
# 绘制
if circles is not None:
for x,y,radius in circles[0]:
#x, y, radius = circles[0][0]
center = (x, y)
cv2.circle(o, center, radius, (0, 255, 0), 2)
'''
#从图像中底部往上跨越,找到相邻2像素且在中心的红色,并标志(此处可以添加误差,以减少寻找时间)
for i in range(476,0,-2):
if b[i][320]!=0 and b[i+2][320]!=0:
cv2.line(img,(0,i),(640,i),(255,255,0),2)
flag=1
break
'''
cv2.imshow('result', o)
cv2.waitKey()
cv2.destroyAllWindows()
参考代码二
import cv2
import numpy as np
def cv_show(img, name):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 第一步读入图片
img = cv2.imread('car.png')
# 第二步:对图片做灰度变化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 第三步:对图片做二值变化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 第四步:获得图片的轮廓值
Binary, contours, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 第五步:在图片中画出图片的轮廓值
draw_img = img.copy()
ret = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
# 第六步:画出带有轮廓的原始图片
cv_show(ret, 'ret')
# 使用另外一个图进行轮廓的测试
# 第一步:载入图片,灰度化和二值化处理,使用cv2.findContours找出轮廓, 使用cv2.drawContours进行画图操作
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img = img.copy()
# 参数说明,draw_img 需要作图的原始图像, contours表示轮廓, 0表示轮廓索引, (0, 0, 255)表示颜色, 2表示线条粗细
ret = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(ret, 'ret')
# 取出单个的轮廓值
cnt = contours[0]
# 第二步:计算轮廓的面积
area = cv2.contourArea(cnt)
# 第三步: 计算轮廓的周长
length= cv2.arcLength(cnt, True)
print(area, length)
# 轮廓近似
img = cv2.imread('contours2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
Binary, contours, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
# 使用周长的倍数作为阈值,阈值越小,图像的轮廓近似与轮廓越近似
epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
draw_img = img.copy()
ret = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(ret, 'ret')
# 外接矩阵
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
res, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
x, y, w, h = cv2.boundingRect(cnt)
ret = cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2)
cv_show(ret, 'ret')
print('矩形面积 / 外接矩形面积', cv2.contourArea(cnt) / (w*h))
# 外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
ret = cv2.circle(ret, center, radius, (0, 255, 0), 2)
cv_show(ret, 'ret')