OpenCV加载图片指定(圆一个坐标,矩形中心点坐标两个坐标)坐标画圆(或者矩形中心点坐标)

&nbsp>&nbsp
&nbsp>&nbsp
&nbsp>&nbsp
OpenCV-Python学习(1)
摘要:安装:开发环境:Win7x64Python3.6.1pycharm4.5.3pip3installopencv-pythonpip3installnumpypip3installMatplotlibopencvversion3.2.0.7numpyversion1.12.1Matplotlibversion2.0.2所有给出的代码均在以上环境下编写测试。译自官网资料http://docs.opencv.org/3.2.0/dc/d4d/tutorial_py_table_of
开发环境:Win7 x64 Python3.6.1pycharm4.5.3pip3 install opencv-pythonpip3 install numpypip3 install Matplotlibopencv version 3.2.0.7numpy version 1.12.1Matplotlib version 2.0.2所有给出的代码均在以上环境下编写测试。译自官网资料http://docs.opencv.org/3.2.0/dc/d4d/tutorial_py_table_of_contents_gui.html开始!目标:读取,显示,保存图片。cv2.imread('文件路径'[,读取方式]) 第一个参数指定文件,图片需要被放在当前工作目录下或者提供绝对路径,第二个参数是用来指定读取方式的标识cv2.IMREAD_COLOR cv2.IMREAD_GRAYSCALE cv2.IMREAD_UNCHANGED或者用1,0,-1代替&即使输入的图片路径是错的,这里也不会报错,但是如果print img会返回Nonecv2.imshow('窗口名',变量) 创建一个窗口显示图片,窗口会自适应图片大小。第一个参数是一个字符串用来指定创建的窗口名,第二个参数是读取图片获得的对象。你可以创建任意个窗口,但是窗口名必须各不相同。cv2.waitKey(milliseconds) 这是个键盘绑定函数。它的参数是毫秒,这个函数等待指定毫秒的键盘事件。如果你在那段时间内按下某个按键,程序就会继续执行。如果参数设为0,它就会无限期等待键盘某个键按下。它也可以被设置为检测某个特定键是否被按下等,下面我们会讨论。另外,键盘输入事件也用于处理很多其他GUI事件,所以你必须只用它来显示图像。cv2.destroyAllWindows() 销毁所有我们创建的窗口。如果你想摧毁指定窗口,使用cv2.destroyWindow('指定窗口名')有一个特殊情况是你可以先创建一个窗口并稍后加载图像到窗口中。这时你可以决定是否调整窗口大小。函数名为cv2.namedWindow()。默认参数cv2.WINDOW_AUTOSIZE。不过如果你把参数修改为cv2.WINDOW_NORMAL,你就可以调整窗口大小了。如果图像面积太大或者给窗口添加trackbar,这个功能就很有用了。cv2.imwrite() 第一个参数是文件名,第二个参数是要保存的图像对象。import cv2import numpy as npimg = cv2.imread('cat.jpg',0)cv2.imshow('My Cat',img)k = cv2.waitKey(0) &; 0xFF if k == 27: #ESC
cv2.destroyAllWindows()elif k == ord('s'): # KEY S
cv2.imwrite('mycat.png',img)
cv2.destroyAllWindows()把我的猫保存成png到工作目录。使用MatplotlibMatplotlib是一个Python绘制库,提供了很多绘制方法。这里你可以看到如何用Matplotlib显示图像,你可以用它缩放图像,保存图像等。import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('cat.jpg',1)plt.imshow(img,interpolation = 'bicubic')plt.xticks([]),plt.yticks([])# to hide tick values on X and Y axisplt.show()warning: opencv用BGR模式加载彩色图像。而Matplotlib用RGB模式显示.所以Matplotlib显示用opencv加载的彩色图像会有区别。相关资源:1.Matplotlib Plotting Styles and Featureshttp://matplotlib.org/api/pyplot_api.html2.BGR和RGB问题http://stackoverflow.com/questions//extracting-a-region-from-an-image-using-slicing-in-python-opencv/74748视频相关:目标:读取,显示,保存视频。通过相机获取视频:我们经常需要通过相机捕获实时流。OpenCV提供一个非常简单的接口。我们来用摄像头获得一段视频(我现在用的笔记本电脑的网络摄像头),把视频转化为灰度视频并显示。你需要创建一个VideoCapture对象来捕获视频。它的参数可以是设备索引或视频文件名。设备索引仅仅是一个数字来指定摄像头。一般来说就只连接一个摄像头。所以我只要传递0或者-1.你可以传递1选择第二个色相头等等。之后,你就可以逐帧获取视频了。但是最后一定不要忘了释放对象。cap.read()返回一个bool(True/False).如果这一贞正确读取了,它就返回True。所以你可以通过检查返回值来检查视频是否结束。有时候,cap可能没有初始化捕获。那么,这段代码就会报错。你可以用cap.isOpened()方法检查它是否被初始化。如果返回True说明初始化过了。否则,用cap.open()打开。你可以用cap.get(propld)方法访问此视频的一些功能,propld一个是0到18的数字。每个数字表示一个视频的特性(如果被该视频应用了的话)。详情请参考cv::VideoCapture::get().有些值可以用cap.set(propld,value)修改,修改后的值就是你想要的新的值。例如,我可以通过cap.get(3)和cap.get(4)检查帧的宽和高。它的默认值是640X480.但是我想把它改成320X240。只要用ret = cap.set(3,320)和ret = cap.set(4,240)就可以了。注意: 如果你程序报错了,先用别的摄像头应用确定下你的摄像头好不好用。import numpy as npimport cv2cap = cv2.VideoCapture(0)while(True):
ret,frame = cap.read() # Capture frame-by-frame
# Our operations on the frame come here
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) &; 0xFF == ord('q'):
break# When everything is done,release the capturecap.release()cv2.destroyAllWindows()播放视频文件:和从色相头捕获视频一样,只要把色相头索引改成视频文件名就好了。同样,在显示帧的时候,给cv2.waitKey()设置一个合适的时间。如果时间太短视频会非常快,如果时间太长,视频又会变得太慢(这其实就是慢动作)。一般情况下使用25毫秒。注意:确定你已经安装了合适的ffmpeg或gstreamer版本。大部分错误都是由错误的ffmpeg/gstreamer版本引起的。import numpy as npimport cv2cap = cv2.VideoCapture('guochan.mp4')while(cap.isOpened()):
ret,frame = cap.read()
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(25) &; 0xFF == ord('q'):
breakcap.release()cv2.destroyAllWindows()保存视频:现在你已经获得视频了,经过逐帧处理,我们要把它保存起来。对于图片来说这是很简单的,只要调用cv2.imwrite().但保存视频还需要先做一点工作。这次我们创建一个VideoWrite对象。我们需要指定输出文件名(例如:不可描述.avi)。然后我们要指定FourCC code。之后是每秒帧数并传递帧大小。最后是isColor标识。如果是True,编码器需要彩色帧,否则它就用灰度帧了。FourCC 是一个4字节代码用于指定视频编译码器(codec)。可供使用的代码列表能在fourcc.org找到。它是依赖于平台的。以下是一些我能用的编译码器(原文作者):In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)In Windows: XVID (我只试用了这个,可以使用)In OSX : *(I don't have access to OSX. Can some one fill this?我也没有苹果,我也不想用它)*FourCC code通过cv2.VideoWriter_fourcc('D','I','V','X')or cv2.VideoWriter_fourcc(*'DIVX')for DIVX.以下代码从色相头获取,垂直翻转每帧并保存。import numpy as npimport cv2cap = cv2.VideoCapture(0)# Define the codec and create VideoWriter objectfourcc = cv2.VideoWriter_fourcc(*'XVID')out = cv2.VideoWriter('bukemiaoshu.avi',fourcc,20.0,(640,480))while(cap.isOpened()):
ret,frame = cap.read()
if ret == True:
frame = cv2.flip(frame,0)
# Write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) &; 0xFF == ord('q'):
break# Release everything if job is finishedcap.release()out.release()cv2.destroyAllWindows()绘制函数:目标:1.学习使用opencv绘制不同几何形状2.学习函数:cv2.line(),cv2.rectangle(),cv2.ellipse(),cv2.putText()等等代码:在所有以上函数中,你经常会看到如下常用参数:1.img:你想在哪张图片上绘制2.color:形状的颜色。BGR中传递元祖例如蓝色(255,0,0)。灰度模式下只需要传递标量值。3.thickness:线或者圆等的厚度。如果传递 -1 给闭合图形,就会填满整个图形,默认值为14.lineType:线的类型,无论是8-connected?anti-aliased(抗锯齿线?)等等(这什么意思)默认是8-connected, cv2.LINE_AA提供抗锯齿线(anti-aliased)能使曲线看起来好看一点。绘制直线:要画一条直线,你需要提供开始和结束的坐标。我们将创建一副黑色的图像并在上面画一条从左上角到右下角的蓝色直线。cv2.line(img,(0,0),(511,511),(255,255,0),5)绘制矩形:画矩形你要提供矩形的左上角和右下角。这次我会在图像的右上角一个绿色的矩形。cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)绘制圆形:绘制圆形,你需要提供圆点坐标和半径。我会把圆放在刚刚的矩形中间。cv2.circle(img,(447,63),63,(0,0,255),-1)绘制椭圆:椭圆就比较烦了,需要传递好几个参数。第一个是圆心坐标(x,y),下一个是轴长(长轴长度,短轴长度)和角的逆时针方向旋转角度。起始角和结束角表示根据椭圆的逆时针长轴计算的开始圆弧和结束圆弧,即赋值0到360,给出整个椭圆。具体参见说明文档,下面将在图像中心画半个椭圆。cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1)绘制多边形:绘制多边形,首先你需要提供各个顶点坐标。把这些点以int32的类型放入形状数组ROWSx1x2中。这里画一个小的4个角的黄色多边形。pts = np.array([[10,5],[20,30],[70,20],[50,10]],np.int32)pts = pts.reshape((-1,1,2))cv2.polylines(img,[pts],True,(0,255,255))注意:如果第三个参数是False,你会得到一条包含所有点的折线,而不是一个闭合的图形。cv2.polylines()可以用来绘制多条线段,只需要创建一个所有线的列表并把它传递给函数。所有线段都会被一条条画出。这比调用cv2.line()逐条绘制快多了。添加文字:你需要指定以下:1.你想写的文字数据2.你想放的位置坐标(即:文字起始点左下角)3.字体类型(查询 cv.2putText()文档)4.字体大小5.相关描述像颜色,粗细,线段类型等。为了好看点,推荐使用 lineType = cv2.LINE_AA。font = cv2.FONT_HERSHEY_SIMPLEXcv2.putText(img,'OpenCV',(10,500),font,4,(255,255,255),2,cv2.LINE_AA)全部代码:import numpy as npimport cv2# Create a black imageimg = np.zeros((512,512,3) , np.uint8)# Create a diagonal blue line with thickness of 5 pxcv2.line(img,(0,0),(511,511),(255,255,0),5)cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)cv2.circle(img,(447,63),63,(0,0,255),-1)cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1)pts = np.array([[10,5],[20,30],[70,20],[50,10]],np.int32)pts = pts.reshape((-1,1,2))cv2.polylines(img,[pts],True,(0,255,255))font = cv2.FONT_HERSHEY_SIMPLEXcv2.putText(img,'OpenCV',(10,500),font,4,(255,255,255),2,cv2.LINE_AA)cv2.imshow('image',img)while(True):
if cv2.waitKey(0) &; 0xFF == ord('q'):
cv2.imwrite('pic.jpg',img)
breakcv2.destroyAllWindows()相关资源1.椭圆中用到的角不是我们的圆角,详情请参考 http://answers.opencv.org/question/14541/angles-in-ellipse-function/用鼠标作画:目标:学会使用函数cv2.setMouseCallback()处理鼠标事件简单例子:我们先画一个简单应用,在我双击的地方画一个圆。首先我创建一个鼠标回调函数,当有鼠标事件发生时就会被执行。鼠标事件可以是任何与鼠标相关的动作,比如左击,右击,左键双击等。每个事件给出一个坐标(x,y)。我们可以使用这个事件和位置信息做任何我们想做的。在python终端中运行以下代码,罗列出所有可用的鼠标事件。&&& import cv2&&& import pprint&&& events = [i for i in dir(cv2) if 'EVENT' in i]&&& pprint.pprint(events)['EVENT_FLAG_ALTKEY',&'EVENT_FLAG_CTRLKEY',&'EVENT_FLAG_LBUTTON',&'EVENT_FLAG_MBUTTON',&'EVENT_FLAG_RBUTTON',&'EVENT_FLAG_SHIFTKEY',&'EVENT_LBUTTONDBLCLK',&'EVENT_LBUTTONDOWN',&'EVENT_LBUTTONUP',&'EVENT_MBUTTONDBLCLK',&'EVENT_MBUTTONDOWN',&'EVENT_MBUTTONUP',&'EVENT_MOUSEHWHEEL',&'EVENT_MOUSEMOVE',&'EVENT_MOUSEWHEEL',&'EVENT_RBUTTONDBLCLK',&'EVENT_RBUTTONDOWN',&'EVENT_RBUTTONUP']&创建鼠标回调函数有一个相同的特定格式。只是具体函数执行的命令不同。那么我们的鼠标回调函数只做一个事情,就是在左键双击的时候画一个圆。import numpy as npimport cv2def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),100,(255,0,0),-1)# Create a black image, a window and bind the function to windowimg = np.zeros((512,512,3),np.int8)cv2.namedWindow('image')cv2.setMouseCallback('image',draw_circle)while(True):
cv2.imshow('image',img)
if cv2.waitKey(20) &; 0xFF == 27:#ESC
cv2.imwrite('mousecir.jpg',img)
breakcv2.destroyAllWindows()高级一点的例子:在下面的例子中,我将根据选择的模式像绘图软件中一样通过拖动鼠标画曲线或者矩形。所以我们的鼠标回调函数分为两个部分,一部分画矩形另一部分画曲线。这个特殊的例子会非常有助于创建和理解某些交互式应用,例如对象跟踪和图像分割等。import numpy as npimport cv2drawing = False # True if mouse is pressedmode = True # if True,draw rectangle.Press 'm' to toggle to curveix,iy = -1,-1# mouse callback functiondef draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
cv2.circle(img,(x,y),5,(0,0,255),-1)# main loopimg = np.zeros((512,512,3),np.uint8)cv2.namedWindow('image')cv2.setMouseCallback('image',draw_circle)while(True):
cv2.imshow('image',img)
k = cv2.waitKey(1) &; 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
cv2.imwrite('draw.jpg',img)
breakcv2.destroyAllWindows()Trackbar用作彩色调色板:目标:1.学习绑定跟踪条(不知道是不是这样翻译)到OpenCV窗口2.学习函数:cv2.getTrackbarPos(),cv2.createTrackbar()示例代码:在这儿我们会创建一个简单的应用用来显示你所指定的颜色。你有一个窗口和三条跟踪条(这么翻译真的low)用于显示颜色和BGR各个指定值。你滑动跟踪条时对应窗口颜色随之改变。默认初始化时颜色设置为黑色。cv2.getTrackbarPos()函数中,第一个参数是跟踪条名字,第二个参数是贴在哪个名字的窗口下,第三个参数是默认值,第四个参数是最大值,第五个参数是每次跟踪条值改变时被执行的回调函数。回调函数总是有一个默认参数用于设置跟踪条位置。在我们这个程序中,函数啥也没做,所以我们直接跳过了。跟踪条的另一个重要应用是作为一个按钮或开关。OpenCV中默认没有按钮功能。所以我们可以使用跟踪条获得这种功能。在我们的应用中,我们创建了一个开关,只有开关处于ON时,否则屏幕一直是黑的。import numpy as npimport cv2def nothing(x):
pass# Create a black image a windowimg = np.zeros((300,512,3),np.uint8)cv2.namedWindow('image')# Create trackbars for color changecv2.createTrackbar('R','image',0,255,nothing)cv2.createTrackbar('G','image',0,255,nothing)cv2.createTrackbar('B','image',0,255,nothing)# Create switch for ON/OFF functionalityswitch = '0:OFF/n1:ON'cv2.createTrackbar(switch,'image',0,1,nothing)while(True):
cv2.imshow('image',img)
k = cv2.waitKey(1) &; 0xFF
if k == 27:
# get current positions of 4 trackbars
r = cv2.getTrackbarPos('R','image')
g = cv2.getTrackbarPos('G','image')
b = cv2.getTrackbarPos('B','image')
s = cv2.getTrackbarPos(switch,'image')
if s == 0:
img[:] = 0
img[:] = [b,g,r]cv2.destroyAllWindows()语言表达能力捉急,将就看看,中年人自娱自乐。
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
邮箱低至5折
推荐购买再奖现金,最高25%
&200元/3月起
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
OpenCV-Python学习(1)相关信息,包括
的信息,所有OpenCV-Python学习(1)相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
支持与服务
资源和社区
关注阿里云
InternationalopenCV 画矩形框或填充矩形
Draws a simple, thick, or filled up-right rectangle.画一个简单或填充的矩形
C++: void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8,int shift=0)函数原型一
C++: void rectangle(Mat& img, Rect r, const Scalar& color, int thickness=1, int lineType=8, int shift=0)函数原型二
Python: cv2.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift ]]])! NoneC: void cvRectangle(CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line Type=8, int shift=0 )函数原型三
Python: cv.Rectangle(img, pt1, pt2, color, thickness=1, lineType=8, shift=0) !NoneParameters参数img – Image.
pt1 – Vertex of the rectangle.
pt2 – Vertex of the recangle opposite to pt1 .
r – Alternative specification of the drawn rectangle.
color – Rectangle color or brightness (grayscale image).
thickness – Thickness of lines that make up the rectangle.
Negative values, like CV_FILLED, mean that the function has to draw a filled rectangle.
lineType – Type of the line. See the line() description.
shift – Number of fractional bits in the point coordinates.
The function rectangle draws a rectangle outline or a filled rectangle whose two opposite corners are pt1 and pt2,
or r.tl() and r.br()-Point(1,1).
#include "stdafx.h"
#include &string&
#include &opencv2\opencv.hpp&
#include "cv.h"
#include "highgui.h"
int main()
IplImage* img = cvLoadImage( "lena.jpg" );
// cvRectangle函数参数: 图片, 左上角, 右下角, 颜色, 线条粗细, 线条类型,点类型
cvRectangle( img, cvPoint(100, 100), cvPoint(200, 200), cvScalar(0, 0, 255), 3, 4, 0 );
cvNamedWindow( "donkeyaime", CV_WINDOW_AUTOSIZE );
cvShowImage( "donkeyaime", img );
cvWaitKey(0);
cvReleaseImage( &img );
#include &string&
#include &opencv2\opencv.hpp&
#include "cv.h"
#include "highgui.h"
R//声明矩形
Point pt1;//点坐标1
Point pt2;//点坐标2
int main()
string imagename = "lena.jpg";
//此处需要填写绝对地址,我测试时使用相对地址出错。
Mat img = imread(imagename);//读入图像
select.x = 50;
select.y = 50;
select.width =100;
select.height =100;
pt1.x = 200;
pt1.y = 200;
pt2.x = 250;
pt2.y = 250;
rectangle(img,select,Scalar(0,0,255),3,8,0);//用矩形画矩形窗
rectangle(img,pt1,pt2,Scalar(0,0,255),3,8,0);//用点画矩形窗
namedWindow("image",1);
imshow("image", img);
waitKey(0);
没有更多推荐了,OpenCV(开源计算机视觉库介绍)|开发技术 - 美国主机支持论坛
查看完整版本: [--
&Pages: ( 2 total )
OpenCV(开源计算机视觉库介绍)
OpenCV是一个用于图像处理、分析、机器视觉方面的开源函数库. &&&&&&无论你是做科学研究,还是商业应用,opencv都可以作为你理想的工具库,因为,对于这两者,它完全是免费的。该库采用C及C++语言编写,可以在windows, linux, mac OSX系统上面运行。该库的所有代码都经过优化,计算效率很高,因为,它更专注于设计成为一种用于实时系统的开源库。opencv采用C语言进行优化,而且,在多核机器上面,其运行速度会更快。它的一个目标是提供友好的机器视觉接口函数,从而使得复杂的机器视觉产品可以加速面世。该库包含了横跨工业产品检测、医学图像处理、安防、用户界面、摄像头标定、三维成像、机器视觉等领域的超过500个接口函数。&&&&&&同时,由于计算机视觉与机器学习密不可分,该库也包含了比较常用的一些机器学习算法。或许,很多人知道,图像识别、机器视觉在安防领域有所应用。但,很少有人知道,在航拍图片、街道图片(例如google street view)中,要严重依赖于机器视觉的摄像头标定、图像融合等技术。&&&&&&近年来,在入侵检测、特定目标跟踪、目标检测、人脸检测、人脸识别、人脸跟踪等领域,opencv可谓大显身手,而这些,仅仅是其应用的冰山一角。&&&&&&如今,来自世界各地的各大公司、科研机构的研究人员,共同维护支持着opencv的开源库开发。这些公司和机构包括:微软,IBM,索尼、西门子、google、intel、斯坦福、MIT、CMU、剑桥。。。尽管之前写过一篇关于OpenCV的介绍(),但依然有朋友对其不甚了解。所以,经常能碰到有人问我诸如以下一些问题:OpenCV能不能实现人脸识别?OpenCV有没有车辆检测的API?OpenCV有没有三维重建的函数?面对这样的问题,我也很困惑。到底该如何给他们解释,才能让它们明白,OpenCV确实很强大,但还没有他们想象中的那么强大。其实,OpenCV的全称,是Open source Computer Vision Library,开放源代码计算机视觉库。也就是说,它是一套关于计算机视觉的开放源代码的API函数库。这也就意味着,(1)不管是科学研究,还是商业应用,都可以利用它来作开发;(2)所有API函数的源代码都是公开的,你可以看到其内部实现的程序步骤;(3)你可以修改OpenCV的源代码,编译生成你需要的特定API函数。但是,作为一个库,它所提供的,仅仅是一些常用的,经典的,大众化的算法的API。一个典型的计算机视觉算法,应该包含以下一些步骤:(1)数据获取(对OpenCV来说,就是图片);(2)预处理;(3)特征提取;(4)特征选择;(5)分类器设计与训练;(6)分类判别;而OpenCV对这六个部分,分别(记住这个词)提供了API。下面我分别就这六个部分来进行一些常见问题的解释。&&&&&&&&对于数据获取,计算机视觉领域的数据,无非就是图片和视频两种。图片,有bmp,jpg,png,tiff....各种压缩和非压缩格式。所以,对压缩格式的图片而言,OpenCV内部必然包含了对应的解压函数(一般都是包含了开源的图片解压函数库,例如,对于jpg压缩格式而言,就包含了libjpg开源库)。而对于视频而言,常见的有.rmvb,.avi,.asf等格式,不同的格式,代表着不同的压缩方法(对于AVI格式,尽管都是avi格式,但内部的压缩算法仍然不相同。原因请见我的令一篇博客:),也就需要对应的解压方法来解压。尽管OpenCV提供了一些读写视频文件的API,但是,它也仅仅是一个接口而已,其内部,依然需要调用想用的视频编解码器的API来进行解码。常用的视频编解码器有:xvid,ffmpeg等。也就是说,如果你想利用OpenCV来进行视频读写之类的操作,是需要安装此类视频编解码器的。安装了相应的视频解码器之后,你就可以调用OpenCV的视频相关API来进行视频文件的读取了,当然,视频文件被解码之后,变成了一张一张的图片,然后才能被OpenCV所处理。另外,还有一种情况,就是数据来自于相机,包括数字相机和模拟相机。不管是哪种相机,你都要想办法获取到相机发送给PC的图片数据(在内存里面可能是jpg格式,也可能是bmp格式),如果,你在PC内存中接收到的是相机发送过来的jpg压缩格式,还需要进行图片数据的内存解压。关于相机和OpenCV的这部分内容,请见我另一篇博客:&&&&&&&&对于预处理,一般就是去除或者降低噪声,光照归一化,亮度归一化,模糊化,锐化,膨胀,腐蚀、开闭等这些操作(详见,冈萨雷斯,《数字图像处理》一书)。而对于这些操作,OpenCV分别(又提到这个词了)提供了相应API函数。而光照的预处理,OpenCV提供了一个直方图均衡化的API,后续可能会提供一些gammar矫正之类的函数。&&&&&&&&对于特征提取,个人认为,可以算是整个计算机视觉系统中最为复杂也最难的部分(纯属个人意见,如若不同,请保留),到底什么是特征,该如何来理解这个看似简单确又包罗万象的名词呢?其实,要想仔细解释,还真的花费很多时间(有兴趣的可以看看,Richard O.Duda(著),李宏东(译),《模式识别》,机械工业出版社)。简单点说,特征,就是一个可以将若干个类别可以尽量分开的一种描述。举例来说,如果你要进行男人和女人的分类,显然,用“身高和体重”这一描述来衡量,是可以的,但是,这两者没有“胸部大小”这一描述更加准确,而“胸部大小”这一描述,又没有“喉结的有无”这一描述更准确。很显然,“身高和体重”,“胸部大小”,“喉结的有无”,这三种描述,都可以用来进行男人和女人的分类,只不过,它们对事物的描述的准确(或者说全面)程度是不同的,而诸如此类的描述,有一个更加专业,叫做“特征”。OpenCV里面,提供了一些特征描述的API,比如,对于人脸检测而言,它提供了haar特征的API,行人检测,提供了hog特征的API,甚至,它提供了LBP纹理特征的API。但是,这些还远远不够。例如,如果你要进行字符识别,OpenCV并没有提供字符识别所对应的特征。这个时候,就需要你自己来编程实现了。当然,该选择什么特征来描述字符呢?哪些特征更好呢?对于这些问题,我建议你去阅读相应的会议,期刊,杂志,硕士、博士毕业论文,看看别人写的文章,自然就知道了。&&&&&&&&对于特征选择,OpenCV并没有提供特定的函数来进行衡量。而特征的分类能力的高低评价,有很多种分析方法,有兴趣的朋友,可以阅读&《机器学习》Tom. Mitchell(著),曾华军(译),机械工业出版社&这本书;&&&&&&&&对于分类器部分,OpenCV提供了SVM,CART,boost,bayes,bdt,ANN,这几种常用的算法。而这些基本已经覆盖了常用的分类器。所以,你需要做的,就是知道怎么调用其接口,各种分类器的优点和缺点(该部分,建议阅读“机器学习”这本书)。&&&&&&&&通过以上的分析,你或许已经发现,OpenCV不过是一个工具库而已。或者,你可以将它理解为积木,而OpenCV中的函数,则可以理解为一个一个的积木块,利用所有或者部分积木块,你可以快速的搭建起来具体的计算机视觉方面的应用(比如,字符识别,车牌识别,遗留物检测)。想必你也已经发现,在利用OpenCV这个积木来搭建具体的计算机视觉应用的时候,真正核心的,应该是这些积木块,如果你明白了积木块的工作原理,那么,是不是就可以不用这些积木块了呢?完全正确!不过,一般部分情况下,我们不需要这么做,因为,OpenCV已经帮你做好了一些工作(已经帮你做好了一些积木块,直接拿来用就是了)。但是,诸如前面提到的特征提取,很多情况下,OpenCV就无能为力了。这个时候,你就需要翻阅计算机视觉、模式识别、机器学习领域顶级会议、期刊、杂志上面发表的文章了。然后,根据这些文章中阐述的原理和方法,来编程实现你要的东西。实际上,也就等于搭建一个属于你私有的积木块。其实,OpenCV中的每一个API函数,也就是这么来的。
决心开始研究OpenCV。闲言少叙,sourceforge网站最近的版本是2011年8月的OpenCV2.3.1,下载安装,我这里使用的开发环境是vs2008,网上搜了一下配置的教程,与之前的几个OpenCV版本的配置过程大体相同:(教程网上很多,知之为知之,不知百度之,我这里粗略再讲一下)1. 配置电脑的环境变量(Path变量)(需要注销才能生效),这里需要注意网上的教程又让增加一个OPENCV变量,值为D:\Program Files\OpenCV2.3.1\build(你安装的路径中的build目录)2. 添加包含文件和库文件,这个和前几个版本方法类似,都是去工具-&选项-&VC目录添加build目录下的include目录及其子目录和你电脑对应版本的lib目录(选择x86 or x64,vc9&&or vc10)下面是第一个实例:新建一个空项目,添加源文件如下:view plain#include &opencv2/core/core.hpp&&&#include &opencv2/highgui/highgui.hpp&&&#include &iostream&&&&&&&&& &&int main( int argc, char** argv )&&{&& &&&&if( argc != 2)&& &&&&{&&&&&& cout &&& Usage: display_image ImageToLoadAndDisplay& &&&&&&&& return -1;&&&&&&}&&&&&&&&&&&&M&&&&&&image = imread(argv[1], CV_LOAD_IMAGE_COLOR);&& // Read the file&&&&&&&&if(! image.data )&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// Check for invalid input&&&&&&{&&&&&&&&&&cout &&&&&Could not open or find the image& && std::&&&&&&&&&&return -1;&&&&&&}&&&&&&&&namedWindow( &Display window&, CV_WINDOW_AUTOSIZE );// Create a window for display.&&&&&&imshow( &Display window&, image );&&&&&&&&&&&&&&&&&& // Show our image inside it.&&&&&&&&waitKey(0);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// Wait for a keystroke in the window&&&&&&return 0;&&}&&这段程序可以在你安装目录下的samples\cpp\tutorial_code\introduction\display_image找到,编译后,将图片test.jpg放到opencvtest.exe相同的目录中去,利用cmd命令行进入的可执行文件所在的目录,运行opencvtest test.jpg则会显示一个图片,第一个程序成功。如图如果遇到找不到tbb_debug.dll文件的问题,参考这里,只是我的环境是vs2008,大同小异。祝你成功!接下来我觉得应该好好研究一下OpenCV里的doc文件夹下的教程和使用手册,我个人觉得《学习OpenCV》这本书已经远远跟不上OpenCV发展的速度了
还是老话题,2.0版本对OpenCV可是进行了大刀阔斧的改革,用c++重新了大部分结构,而不是1.X版本中的c结构。这些模块包括:core——定义了基本数据结构,包括最重要的Mat和一些其他的模块imgproc——该模块包括了线性和非线性的图像滤波,图像的几何变换,颜色空间转换,直方图处理等等video——该模块包括运动估计,背景分离,对象跟踪calib3d——基本的多视角几何算法,单个立体摄像头标定,物体姿态估计,立体相似性算法,3D信息的重建features2d——显著特征检测,描述,特征匹配objdetect——物体检测和预定义好的分类器实例(比如人脸,眼睛,面部,人,车辆等等)highgui——视频捕捉、图像和视频的编码解码、图形交互界面的接口gpu——利用GPU对OpenCV模块进行加速算法ml——机器学习模块(SVM,决策树,Boosting等等)flann——Fast Library for Approximate Nearest Neighbors(FLANN)算法库legacy——一些已经废弃的代码库,保留下来作为向下兼容还有一些其他的模块,比如FLANN算法库、Google测试包、Python bingdings等等
自从版本2.0,OpenCV采用了新的数据结构,用Mat类结构取代了之前用extended C写的cvMat和lplImage,更加好用啦,最大的好处就是更加方便的进行内存管理,对写更大的程序是很好的消息。需要注意的几点:1. Mat的拷贝只是复制了Mat的信息头,数据的指针也指向了被拷贝的数据地址,而没有真正新建一块内存来存放新的矩阵内容。这样带来的一个问题就是对其中一个Mat的数据操作就会对其他指向同一块数据的Mat产生灾难性的影响。2.建立多维数组的格式是这样的view plainint sz[3] = {2, 2, 2};&&Mat L(3, sz, CV_8UC(1), Scalar::all(0));&&3.传统的lplImage格式也可直接转换为Mat格式view plainIplImage* img = cvLoadImage(&greatwave.png&, 1);&&Mat mtx(img); // convert IplImage* -& Mat&&如果想将新版本的Mat格式转换为老版本,则需要如下调用:view plainMat I;&&IplImage* pI = &I.operator IplImage();&&CvMat* mI = &I.operator CvMat();&&不过更安全的调用格式为:view plainPtr&IplImage& piI = &I.operator IplImage();&&4.Mat结构更加友好,很多操作更接近matlab的风格5.也有Point2f,Point3f,vector等数据结构可以使用6.RNG类可以产生随机数7.实现颜色通道的分离使用函数split
2.0新版本对数据结构进行了大幅修改:定义了DataType类定义了Point_模板类,取代了之前版本的CvPoint、CvPoint2D32f定义了Point3_模板类,取代了之前版本的CvPoint2D32f定义了Size_模板类,取代了之前版本的CvSize和CvSize2D32f定义了Rect_模板类,取代了之前版本的CvRectRotatedRect模板类,TermCriteria模板类,取代了之前的CvTermCriteria,这个类是作为迭代算法的终止条件的,这个类在参考手册里介绍的很简单,我查了些资料,这里介绍一下。该类变量需要3个参数,一个是类型,第二个参数为迭代的最大次数,最后一个是特定的阈值Matx模板类。Matx模板类是对Mat类的一个拓展,从Matx类有派生出Vec类,又Vec类又派生出Scalar_类,取代了CvScalar定义了Range类指定了一个序列的一个连续的子序列定义了Ptr类用来对老版本的数据结构进行指针操作,更安全有效,可以防止内存的不正常使用。最最重要的定义了Mat类来表示矩阵,取代了之前的CvMat和lplImage。Mat结构支持的操作有:构造析构函数Mat和~Mat对=、MatExpr、( )、CvMat、IplImage进行了运算符重载row、col函数rowRange、colRange类似matlab的运算操作diag、t、inv、mul、cross、dot、zeros、one、eye复制转换变形clone、copyTo、convertTo、assignTo、setTo、reshape、create、addref其中copyTo函数有个妙用,不但可以复制Mat,还可以通过mask提取出感兴趣的部分数据的操作release、resize、reserve、push_back、pop_back、locateROI、adjustROIMat的信息total、isContinuous、elemSize、elemSize1、type、depth、channes、step1、size、empty定位ptr、at、begin、end还做了几个扩展类Mat_、NAryMatlterator、SparseMat、SparseMat_取代了之前的CvSparseMat。这些类的操作运算与Mat大同小异,类声明参考core的具体头文件当然,新版本对老版本的数据结构和函数依然支持。新版本还在这些结构里支持dft、dct变换,我这里讲一下我的新发现PCA类、SVD类PCA类有构造函数PCA,运算符重载(),project,backProject。SVD类有构造函数SVD,运算符重载(),compute,solveZ,backSubst这里介绍几个我使用过的实用函数:inRange函数可以检查Matsrc的内容是否在Matlower、Matupper之间,输出结果是一个uchar型矩阵,1表示在两者之间,否则为0,值得注意的是,Matlower,Matupper也可以用Scalar的格式bitwise_xxx函数对两个矩阵进行位运算,结果保存在第三个矩阵当中mixChannels函数可以实现矩阵的指定通道复制到新矩阵的指定通道总之,新版本支持更多的数学运算,还支持一些画图操作
都知道,2.0版本对之前的OpenCV数据结构进行了大幅度的修改。但对之前版本的兼容是一个很重要的事情。这节就主要讨论这个问题首先来看一下2.0版本对之前版本的进行了哪些修改1.采用了新的数据结构Mat作为图像的容器,取代了之前的CvMat和lplImage,这个改动不是太复杂,只需适应一下新东西,而且可以自由转换view plainMat I;&&IplImage pI = I;&&CvMat mI = I;&&对于指针的操作要相对复杂一些,而且还要注意内存的释放,我这里不推荐用老版本的数据结构,例如:view plainMat I;&&IplImage* pI = &I.operator IplImage();&&CvMat* mI = &I.operator CvMat();&&2.对library进行了重组,将原来的一个大库根据功能结构分成具体小库,这样包含头文件的时候只需要加入你需要的库,只是原来库的子集3.使用了cv 这个namespace来防止和其他的library 结构冲突。所以在使用的时候也要预先加上cv::关键字,这也是新版本的函数,数据都省略了cv前缀的原因,一般放在include之后,格式为:view plain // The new C++ interface API is inside this namespace. Import it.&&
1. XML、YAML文件的打开和关闭XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如:view plainstring filename = &I.xml&;&&FileStorage fs(filename, FileStorage::WRITE);&&\\...&&fs.open(filename, FileStorage::READ);&&文件关闭操作会在FileStorage结构销毁时自动进行,但也可调用如下函数实现view plainfs.release();&&2.文本和数字的输入和输出写入文件使用&&&&&&运算符,例如:view plainfs && &iterationNr& && 100;&&读取文件,使用 && 运算符,例如view plainint itNr;&&fs[&iterationNr&] && itNr;&&itNr = (int) fs[&iterationNr&];&&3. OpenCV数据结构的输入和输出,和基本的C++形式相同view plainMat R = Mat_&uchar &::eye (3, 3),&&T = Mat_&double&::zeros(3, 1);&&fs && &R& && R; // Write cv::Mat&&fs && &T& && T;&&fs[&R&] && R; // Read cv::Mat&&fs[&T&] && T;&&4. vector(arrays) 和 maps的输入和输出vector要注意在第一个元素前加上“[”,在最后一个元素前加上&]&。例如:view plainfs && &strings& && &[&; // text - string sequence&&fs && &image1.jpg& && &Awesomeness& && &baboon.jpg&;&&fs && &]&; // close sequence&&对于map结构的操作使用的符号是&{&和&}&,例如:view plainfs && &Mapping&; // text - mapping&&fs && &{& && &One& && 1;&&fs && &Two& && 2 && &}&;&&读取这些结构的时候,会用到FileNode和FileNodeIterator数据结构。对FileStorage类的[]操作符会返回FileNode数据类型,对于一连串的node,可以使用FileNodeIterator结构,例如:view plainFileNode n = fs[&strings&]; // Read string sequence - Get node&&if (n.type() != FileNode::SEQ)&&{&&cerr && &strings is not a sequence! FAIL& &&&&return 1;&&}&&FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node&&for (; it != it_ ++it)&&cout && (string)*it &&&&5. 读写自己的数据结构这部分比较复杂,参考最后的实例中的MyData结构自己领悟吧最后,我这里上一个实例,供大家参考。源文件里填入如下代码:view plain#include &opencv2/core/core.hpp&&&#include &iostream&&&#include &string&&&&&&&&&&&void help(char** av)&&{&&&&&&cout && endl&& &&&&&&&&&& av[0] && & shows the usage of the OpenCV serialization functionality.&&&&&&&&& && endl&&&&&&&&&&&& &usage: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& endl&&&&&&&&&&&&&&av[0] && & outputfile.yml.gz&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& && endl&&&&&&&&&&&& &The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by &&&&&&&&&&&&& &specifying this in its extension like xml.gz yaml.gz etc... &&&&&&&&&&&&&&&&&&&&& endl&&&&&&&&&&&& &With FileStorage you can serialize objects in OpenCV by using the && and && operators& && endl&&&&&&&&&&&& &For example: - create a class and have it serialized&&&&&&&&&&&&&&&&&&&&&&&&& && endl&&&&&&&&&&&& &&&&&&&&&&&&& - use it to read and write matrices.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&class MyData&&{&&public:&&&&&&MyData() : A(0), X(0), id()&&&&&&{}&&&&&&explicit MyData(int) : A(97), X(CV_PI), id(&mydata1234&) // explicit to avoid implicit conversion&&&&&&{}&&&&&&void write(FileStorage& fs) const&&&&&&&&&&&&&&&&&&&&&&&&//Write serialization for this class&&&&&&{&&&&&&&&&&fs && &{& && &A& && A && &X& && X && &id& && id && &}&;&&&&&&}&&&&&&void read(const FileNode& node)&&&&&&&&&&&&&&&&&&&&&&&&&&//Read serialization for this class&&&&&&{&&&&&&&&&&A = (int)node[&A&];&&&&&&&&&&X = (double)node[&X&];&&&&&&&&&&id = (string)node[&id&];&&&&&&}&&public:&& // Data Members&&&&&&int A;&&&&&&double X;&&&&&&&&};&&&&//These write and read functions must be defined for the serialization in FileStorage to work&&void write(FileStorage& fs, const std::string&, const MyData& x)&&{&&&&&&x.write(fs);&&}&&void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){&&&&&&if(node.empty())&&&&&&&&&&x = default_&&&&&&else&&&&&&&&&&x.read(node);&&}&&&&// This function will print our custom class to the console&&ostream& operator&&(ostream& out, const MyData& m)&& {&& &&&&out && &{ id = & && m.id && &, &;&&&&&&out && &X = & && m.X && &, &;&&&&&&out && &A = & && m.A && &}&;&&&&&&&&}&&&&int main(int ac, char** av)&&{&&&&&&if (ac != 2)&&&&&&{&&&&&&&&&&help(av);&&&&&&&&&&return 1;&&&&&&}&&&&&&&&string filename = av[1];&&&&&&{ //write&&&&&&&&&&Mat R = Mat_&uchar&::eye(3, 3),&&&&&&&&&&&&&&T = Mat_&double&::zeros(3, 1);&&&&&&&&&&MyData m(1);&&&&&&&&&&&&FileStorage fs(filename, FileStorage::WRITE);&&&&&&&&&&&&fs && &iterationNr& && 100;&&&&&&&&&&fs && &strings& && &[&;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// text - string sequence&&&&&&&&&&fs && &image1.jpg& && &Awesomeness& && &baboon.jpg&;&&&&&&&&&&fs && &]&;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // close sequence&&&&&&&&&&&&&&&&&&&&fs && &Mapping&;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// text - mapping&&&&&&&&&&fs && &{& && &One& && 1;&&&&&&&&&&fs &&&&&&&&&&&Two& && 2 && &}&;&&&&&&&&&&&&&&&& &&&&&&&&&&fs && &R& && R;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// cv::Mat&&&&&&&&&&fs && &T& && T;&&&&&&&&&&&&fs && &MyData& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// your own data structures&&&&&&&&&&&&fs.release();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // explicit close&&&&&&&&&&cout && &Write Done.& &&&&&&&&}&&&&&&&&{//read&&&&&&&&&&cout && endl && &Reading: & &&&&&&&&&&&&FileS&& &&&&&&&&fs.open(filename, FileStorage::READ);&&&&&&&&&&&&int itNr;&& &&&&&&&&//fs[&iterationNr&] && itNr;&&&&&&&&&&itNr = (int) fs[&iterationNr&];&&&&&&&&&&cout && itNr;&&&&&&&&&&if (!fs.isOpened())&&&&&&&&&&{&&&&&&&&&&&&&&cerr && &Failed to open & && filename &&&&&&&&&&&&&&&&help(av);&&&&&&&&&&&&&&return 1;&&&&&&&&&&}&&&&&&&&&&&&FileNode n = fs[&strings&];&&&&&&&&&&&&&&&&&&&&&&&& // Read string sequence - Get node&&&&&&&&&&if (n.type() != FileNode::SEQ)&&&&&&&&&&{&&&&&&&&&&&&&&cerr && &strings is not a sequence! FAIL& &&&&&&&&&&&&&&&&return 1;&&&&&&&&&&}&&&&&&&&&&&&FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node&&&&&&&&&&for (; it != it_ ++it)&&&&&&&&&&&&&&cout && (string)*it &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&n = fs[&Mapping&];&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// Read mappings from a sequence&&&&&&&&&&cout && &Two&&& && (int)(n[&Two&]) && &; &;&& &&&&&&&&cout && &One&&& && (int)(n[&One&]) && endl &&&& &&&&&&&&&&&&&&&&&&&&MyD&&&&&&&&&&Mat R, T;&&&&&&&&&&&&fs[&R&] && R;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// Read cv::Mat&&&&&&&&&&fs[&T&] && T;&&&&&&&&&&fs[&MyData&] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // Read your own structure_&&&&&&&&&&&&cout && endl&& &&&&&&&&&&&&&& &R = & && R &&&&&&&&&&&&cout && &T = & && T && endl &&&&&&&&&&&&cout && &MyData = & && endl && m && endl &&&&&&&&&&&&&&//Show default behavior for non existing nodes&&&&&&&&&&cout && &Attempt to read NonExisting (should initialize the data structure with its default).&;&&&&&&&&&&&&fs[&NonExisting&] &&&&&&&&&&&&cout && endl && &NonExisting = & && endl && m &&&&&&&&}&&&&&&&&cout && endl&& &&&&&&&&&& &Tip: Open up & && filename && & with a text editor to see the serialized data.& &&&&&&&&&&return 0;&&}&&编译后,在命令行进入到文件目录,执行test test.xml,运行结果如下,生成一个test . xml文件,内容如下:view plain&&&?xml version=&1.0& ?&&& - &opencv_storage&&&&&&iterationNr&100&/iterationNr&&& &&&strings&image1.jpg Awesomeness baboon.jpg&/strings&&& - &Mapping&&&&&&One&1&/One&&& &&&Two&2&/Two&&& &&&/Mapping&&&- &R type_id=&opencv-matrix&&&&&&&rows&3&/rows&&& &&&cols&3&/cols&&& &&&dt&u&/dt&&& &&&data&1 0 0 0 1 0 0 0 1&/data&&& &&&/R&&&- &T type_id=&opencv-matrix&&&&&&&rows&3&/rows&&& &&&cols&1&/cols&&& &&&dt&d&/dt&&& &&&data&0. 0. 0.&/data&&& &&&/T&&&- &MyData&&&&&&A&97&/A&&& &&&X&3.&/X&&& &&&id&mydata1234&/id&&& &&&/MyData&&&&&&/opencv_storage&&&
先介绍几个最基本的核滤波器相关的类2D图像滤波器基础类BaseFilter:dst(x,y) = F(src(x,y), src(x+1,y)... src(x+wdith-1,y), src(y+1,x)... src(x+width-1, y+height-1) ); 相关的调用函数为getLinearFilter、getMorphologyFilter单行核滤波器基础类BaseRowFilter:dst(x,y) = F(src(x,y), src(x+1,y),...src(x+width-1,y));相关的调用函数为getLinearRowFilter、getMorphologyRowFilter单列核滤波器基础类BaseColumnFilter:dst(x,y) = F(src(x,y), src(x,y+1),...src(x,y+width-1));相关的调用函数为getColumnSumFilter、getLinearColumnFilter、getMorphologyColumnFilter类FilterEngine:该类可以应用在对图像的任意滤波操作当中,在OpenCV滤波器函数中扮演着很重要的角色,相关的函数有createBoxFitler、createDerivFitlter、createGaussianFilter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter基于这些类有一些基本的滤波器bilateralFilter、blur、boxFilter还有一些形态学操作如:dilate、erode、morphologyEx还有基于核和图像卷积的滤波器filter2D还有一些典型的滤波器如GaussianBlur、medianBlur、Laplacian、pyrMeanShiftFiltering、sepFilter2D还有Sobel、Scharr运算符其他一些函数有borderInterpolate、buildPyramid、copyMakeBorder、createBoxFilter、createDirivFilter、createGaussianFliter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter、getDerivKernels、getGaussianKernel、getKernelType、getStructuringElement、pyrDown、pyrUp还老版本的滤波器cvSmooth这里介绍一下我使用Laplacian滤波的心得,这个函数的第三个参数为输出的图像的深度,注意经过拉普拉斯算子处理后得到的值是有正有负的,所以输出图像的深度最好为输入图像深度的2倍,才能有效防止数据溢出,如必须要使用8位的数据,可以再使用函数convertScaleAbs处理。而且要注意使用的拉普拉斯算子掩膜的中心系数为负。
直方图histograms也是图像处理中经常用到的一种手段。新版本对直方图不再使用之前的histogram的形式,而是用统一的Mat或者MatND的格式来存储直方图,可见新版本Mat数据结构的优势。先介绍下其相关的函数calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了这几个常用的函数以为,还有一些c函数写的直方图类CvHistogram的相关操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGHcalcHist函数为计算图像的直方图,使用方法如下:view plain// C++:&& void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )&&// C++:&& void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )&&arrays为输入图像指针,narrays为输入图像的个数,channels为用来计算直方图的通道列表,mask为掩膜矩阵,不为空的时候,只计算arrays中的掩膜区域的直方图,hist为输出的直方图矩阵,dims为直方图矩阵的维度,histSize为每一维直方图矩阵的大小,ranges为每一维直方图元素的取值范围,是一个2维数组的地址,uniform为直方图是否为统一模式,统一模式下会拉伸为range的大小,accumulate为累计标志,方便直方图的更新,不需要重新计算举几个实例方便大家理解:对于图像为灰度图,调用方式如下:view plainint histSize = 255;&&float ranges[] = {0, 255};&&const float* histRange = {ranges};&&calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);&&直方图的归一化已经不再适合cvNormalizeHist这个函数了,只需要用对矩阵的归一化函数normalize就可以实现了。直方图均衡化函数为equalizeHist,这个函数比较简单,这里就不详细介绍了直方图的比较函数为compareHist,函数返回值为两矩阵的相似程度,相似度衡量的办法目前支持4种– CV_COMP_CORREL Correlation相关系数,相同为1,相似度范围为[ 1, 0 )– CV_COMP_CHISQR Chi-Square卡方,相同为0,相似度范围为[ 0, +inf )– CV_COMP_INTERSECT Intersection直方图交,数越大越相似,,相似度范围为[ 0, +inf )– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常态分别比对的Bhattacharyya 距离,相同为0,,相似度范围为[ 0, +inf )计算反向投影图函数为calcBackProject。所谓反向投影图就是一个概率密度图。calcBackProject的输入为图像及其直方图,输出与待跟踪图像大小相同,每一个像素点表示该点为目标区域的概率。这个点越亮,该点属于物体的概率越大。关于反向直方图,可以参考一下这篇文章,这个函数使我们利用特征直方图寻找图片中的特征区域变得更加方便容易。这里举一个比较常用的例子:如果已经有一个肤色的特征直方图,则可以在待检测图像中利用直方图方向投影图找出图片中的肤色区域。
直方图histograms也是图像处理中经常用到的一种手段。新版本对直方图不再使用之前的histogram的形式,而是用统一的Mat或者MatND的格式来存储直方图,可见新版本Mat数据结构的优势。先介绍下其相关的函数calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了这几个常用的函数以为,还有一些c函数写的直方图类CvHistogram的相关操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGHcalcHist函数为计算图像的直方图,使用方法如下:view plain// C++:&& void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )&&// C++:&& void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )&&arrays为输入图像指针,narrays为输入图像的个数,channels为用来计算直方图的通道列表,mask为掩膜矩阵,不为空的时候,只计算arrays中的掩膜区域的直方图,hist为输出的直方图矩阵,dims为直方图矩阵的维度,histSize为每一维直方图矩阵的大小,ranges为每一维直方图元素的取值范围,是一个2维数组的地址,uniform为直方图是否为统一模式,统一模式下会拉伸为range的大小,accumulate为累计标志,方便直方图的更新,不需要重新计算举几个实例方便大家理解:对于图像为灰度图,调用方式如下:view plainint histSize = 255;&&float ranges[] = {0, 255};&&const float* histRange = {ranges};&&calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);&&直方图的归一化已经不再适合cvNormalizeHist这个函数了,只需要用对矩阵的归一化函数normalize就可以实现了。直方图均衡化函数为equalizeHist,这个函数比较简单,这里就不详细介绍了直方图的比较函数为compareHist,函数返回值为两矩阵的相似程度,相似度衡量的办法目前支持4种– CV_COMP_CORREL Correlation相关系数,相同为1,相似度范围为[ 1, 0 )– CV_COMP_CHISQR Chi-Square卡方,相同为0,相似度范围为[ 0, +inf )– CV_COMP_INTERSECT Intersection直方图交,数越大越相似,,相似度范围为[ 0, +inf )– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常态分别比对的Bhattacharyya 距离,相同为0,,相似度范围为[ 0, +inf )计算反向投影图函数为calcBackProject。所谓反向投影图就是一个概率密度图。calcBackProject的输入为图像及其直方图,输出与待跟踪图像大小相同,每一个像素点表示该点为目标区域的概率。这个点越亮,该点属于物体的概率越大。关于反向直方图,可以参考一下这篇文章,这个函数使我们利用特征直方图寻找图片中的特征区域变得更加方便容易。这里举一个比较常用的例子:如果已经有一个肤色的特征直方图,则可以在待检测图像中利用直方图方向投影图找出图片中的肤色区域。
OpenCV提供一个功能强大的UI接口,可以在MFC、Qt、WinForms、Cocoa等平台下使用,甚至不需要其他的平台。新版本的HighGUI接口包括:创建并控制窗口,该窗口可以显示图片并记录其内容为窗口添加了trackbars控件,可以方便利用鼠标进行控制而不是之前版本的只能利用键盘读写硬盘和内存的图片读取摄像头的视频、读写视频文件先来介绍UI,包括函数createTrackbar、getTrackbarPos、setTrackbarPos、imshow、namedWindow、destroyWindow、destroyAllWindows、MoveWindow、ResizeWindow、SetMouseCallback、waitKey。这些函数保证了图像的基本处理、tarckbar的控制和鼠标键盘的响应介绍一下读写图像视频的函数:图像相关的函数有imdecode、imencode、imread、imwrite。读取视频相关为VideoCapture类,负责捕捉文件和摄像头的视频,该类内有成员函数VideoCapture、open、isOpened、release、grab、retrieve、read、get、set,写视频的类为VideoWriter,类内有成员函数VideoWriter、open、isOpened、write新版本还为Qt做了新函数,这里就不介绍了,有兴趣的朋友可以自己看一下参考手册的第四章第三节。这里介绍几个常用的新功能,首先介绍一下添加滑杆控件Trackbar。调用函数为:view plaincreateTrackbar( TrackbarName, &Linear Blend&, &alpha_slider, alpha_slider_max, on_trackbar );&&第一个参数为字符串作为标签,第二个参数为所在窗口的名字,第三个参数为存储滑杆位置的值地址,其范围为0~alpha_slider_max(第四个参数),最后一个参数为移动滑杆时调用的回调函数名。OpenCV2.0版本加强了对视频处理的支持,不再需要对一组连续的图片进行处理,可以进行实时的图像采集和记录以及存储。视频的操作基本都被封装在VideoCapture类中。打开视频可以可以通过如下代码实现:view plainVideoCapture captRefrnc(sourceReference);&&// or&&VideoCapture captUndT&&captUndTst.open(sourceCompareWith);&&其中sourceReference和sourceCompareWith为string型,为文件名。还可以通过isOpened函数检测视频是否成功打开。也可以调用release函数提前关闭视频。还可以讲VideoCapture放到Mat结构中,因为视频流是一连串的,可以通过read函数或&&操作符逐帧的读取,例如:view plainMat frameReference, frameUnderT&&captRefrnc && frameR&&captUndTst.open(frameUnderTest);&&read函数只能逐帧的抓取,如果要抓取某一帧,可以成对的调用grab函数和retrieve函数。get函数可以获取视频相关信息。set函数可以控制视频的一些值,比如是指视频的当前位置或帧数。可以使用VideoWriter类创建新视频,其open,isOpened函数调用方法类似,write函数或&&运算符向视频写入内容,可以使用split函数和merge函数单独调整RGB通道的值今日,被一个网友指出,说OpenCV以前提供的读写功能采用VFW,效率低下且有些格式支持不好。而 OpenCV 2.0 内置了videoInput Library,可以自动在VFW和DirectShow间切换。videoInput是老外写的功能强大的开源视频处理库。是一个第三方库,2.0~2.2的版本专门有一个3rdparty对该库进行支持,而在最新的2.3版本中,已经讲videoInput库集成到highgui中了,想使用它的话,只需要在cmake中设置宏WITH_VIDEOiNPUT=OFF/ON即可。以后有新学到的东西都会陆续补充进来。
Templates是c++的一个很强大的特征,可以是数据结构更加安全高效。但也会增加编译时间和代码的长度,当函数被频繁调用的时候便步那么高效,所以在目前的OpenCV版本不推荐过多的使用templates。矩阵元素可以是如下类型中的一种:? 8-bit unsigned integer (uchar)? 8-bit signed integer (schar)? 16-bit unsigned integer (ushort)? 16-bit signed integer (short)? 32-bit signed integer (int)? 32-bit ?oating-point number (?oat)? 64-bit ?oating-point number (double)对于这些数据类型又定义了如下的枚举变量:view plainenum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };&&view plainCV_32FC1 == CV_32F;&&CV_32FC2 == CV_32FC(2) == CV_MAKETYPE(CV_32F, 2);&&CV_MAKETYPE(depth, n) == ((x&7)&&3) + (n-1);&&
用OpenCV做算法的朋友们肯定为随机数烦恼过,新版本一直支持随机数产生器啦,而且还继续支持之前版本的c格式的函数,不过与时俱进,我这里介绍C++的RNG类。它可以压缩一个64位的i整数并可以得到scalar和array的随机数。目前的版本支持均匀分布随机数和Gaussian分布随机数。随机数的产生采用的是Multiply-With-Carry算法和Ziggurat算法。其构造函数的初始化可以传入一个64位的整型参数作为随机数产生器的初值。next可以取出下一个随机数,uniform函数可以返回指定范围的随机数,gaussian函数返回一个高斯随机数,fill则用随机数填充矩阵。这里介绍一个uniform的使用事项,就是比如利用它产生0~1的随机数的问题,具体代码如下:view plainRNG&&// always produces 0&&double a = rng.uniform(0, 1);&&// produces double from [0, 1)&&double a1 = rng.uniform((double)0, (double)1);&&// produces float from [0, 1)&&double b = rng.uniform(0.f, 1.f);&&// produces double from [0, 1)&&double c = rng.uniform(0., 1.);&&// may cause compiler error because of ambiguity:&&// RNG::uniform(0, (int)0.999999)? or RNG::uniform((double)0, 0.99999)?&&double d = rng.uniform(0, 0.999999);&&就是不能写成rng.uniform( 0 , 1),因为输入为int型参数,会调用uniform(int,int),只能产生0。请大家注意使用^_^还有一些随机数相关的函数,比如randu可以产生一个均匀分布的随机数或者矩阵,randn可以产生一个正态分布的随机数,randShuffle可以随机打乱矩阵元素再简单介绍一下c版本的随机数产生器的相关函数,有cvRNG、cvRandArr、cvRandInt、cvRandReal
寻找一幅图像的匹配的模板,可以在一段视频里寻找出我们感兴趣的东西,比如条形码的识别就可能需要这样类似的一个工作提取出条形码区域(当然这样的方法并不鲁棒)。而OpenCV已经为我们集成好了相关的功能。函数为matchTemplate。所谓模板匹配就是在一幅图像中寻找和模板图像(patch)最相似的区域。该函数的功能为,在输入源图像Source image(I)中滑动框,寻找各个位置与模板图像Template image(T)的相似度,并将结果保存在结果矩阵result matrix(R)中。该矩阵的每一个点的亮度表示与模板T的匹配程度。然后可以通过函数minMaxLoc定位矩阵R中的最大值(该函数也可以确定最小值)。匹配的方法有:CV_TM_SQDIFF 平方差匹配法,最好的匹配为0,值越大匹配越差CV_TM_SQDIFF_NORMED 归一化平方差匹配法CV_TM_CCORR 相关匹配法,采用乘法操作,数值越大表明匹配越好CV_TM_CCORR_NORMED 归一化相关匹配法CV_TM_CCOEFF 相关系数匹配法,最好的匹配为1,-1表示最差的匹配CV_TM_CCOEFF_NORMED 归一化相关系数匹配法前面两种方法为越小的值表示越匹配,后四种方法值越大越匹配。其实模板匹配的使用和直方图反向投影calcBackProject函数很像,只是直方图反向投影对比的是直方图,而模板匹配对比的是图像的像素值,相比较而言,直方图反向投影的匹配鲁棒性更好。总结这个函数,感觉功能不是很强大,应用不是很广,因为只能在图像中搜索出指定的模板,如果模板是从待搜索目标中截取出来的,效果会很好,如果模板不是待搜素图像的一部分,效果就差的多了,所以该函数的使用还是有很大的局限性。
OpenCV支持大量的轮廓、边缘、边界的相关函数,相应的函数有moments、HuMoments、findContours、drawContours、approxPolyDP、arcLength、boundingRect、contourArea、convexHull、fitEllipse、fitLine、isContourConvex、minAreaRect、minEnclosingCircle、mathcShapes、pointPolygonTest。还有一些c版本的针对老版本的数据结构的函数比如cvApproxChains、cvConvexityDefects。这里先介绍一些我用过的函数,以后用到再陆续补充。OpenCV里支持很多边缘提取的办法,可是如何在一幅图像里得到轮廓区域的参数呢,这就需要用到findContours函数,这个函数的原型为:view plain//C++:&& void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())&&void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point())&&这里介绍下该函数的各个参数:输入图像image必须为一个2值单通道图像contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。mode表示轮廓的检索模式CV_RETR_EXTERNAL表示只检测外轮廓CV_RETR_LIST检测的轮廓不建立等级关系CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demomethod为轮廓的近似办法CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。具体应用参考sample文件夹下面的squares.cpp这个demofindContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选findContours经常与drawContours配合使用,用来将轮廓绘制出来。其中第一个参数image表示目标图像,第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,第四个参数color为轮廓的颜色,第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,第六个参数lineType为线型,第七个参数为轮廓结构信息,第八个参数为maxLevel得到了复杂轮廓往往不适合特征的检测,这里再介绍一个点集凸包络的提取函数convexHull,输入参数就可以是contours组中的一个轮廓,返回外凸包络的点集还可以得到轮廓的外包络矩形,使用函数boundingRect,如果想得到旋转的外包络矩形,使用函数minAreaRect,返回值为RotatedRect;也可以得到轮廓的外包络圆,对应的函数为minEnclosingCircle;想得到轮廓的外包络椭圆,对应的函数为fitEllipse,返回值也是RotatedRect,可以用ellipse函数画出对应的椭圆如果想根据多边形的轮廓信息得到多边形的多阶矩,可以使用类moments,这个类可以得到多边形和光栅形状的3阶以内的所有矩,类内有变量m00,m10,m01,m20,m11,m02,m30,m21,m12,m03,比如多边形的质心为 x = m10 / m00,y = m01 / m00。如果想获得一点与多边形封闭轮廓的信息,可以调用pointPolygonTest函数,这个函数返回值为该点距离轮廓最近边界的距离,为正值为在轮廓内部,负值为在轮廓外部,0表示在边界上。
先简单回顾一下计算机视觉的知识。这里研究生的摄像机模型都是针孔摄像机,摄像机的标定问题是CV领域的一个入门级的问题,初学摄像机标定时会被各种坐标系弄晕,这里再介绍一下,常提到的坐标系有四个:世界坐标系(Ow,以空间一点为原点)、摄像机坐标系(Oc以小孔即光心为原点)、图像物理坐标系(O1以像平面中心为原点)、图像像素坐标系(O以像平面左下角为原点)。这样再看相关资料的时候就不会混了吧,这里再介绍一篇张正友的摄像机定标办法的相关资料其参数分为内参数和外参数:内参数是摄像机坐标系和理想坐标系之间的关系(5个内参数,分别为α、β、u0、v0、θ);外参数表示摄像机在世界坐标系里的位置和方向(6个外参数,3个表示旋转R的角度,3个表示平移t)。利用calibrateCamera函数可以得到这些内外参数,而calibrationMatrixValues可以得到摄像机投影透视方程的投影矩阵,composeRT可以合并两个旋转平移变换,computeCorrespondEpilines计算其他图像的相应epilines,convertPointsToHomogeneous把点从欧式空间转换到齐次空间,convertPointsFromHomogeneous把点从齐次空间变换到欧式空间,而函数convertPointsHomogeneous把上述两个函数功能综合到一起了,decomposeProjectionMatrix可以将矩阵分解,drawChessboardCorners获得检测棋盘的角,findChessboardCorners获得棋盘的内角点位置,findCirclesGrid得到圆圈光栅的中心,solvePnP实现物体位置的3维坐标和2维坐标之间的转换,solvePnPRansac利用RANSAC实现上述功能,findFundamentalMat计算两幅图像关联点的基础矩阵,findHomography找出两个平面的透视变换,estimateAffine3D计算两个3维点集的理想仿射变换,filterSpeckles可以过滤不同块的小斑点,getOptimalNewCameraMatrix得到自由比例参数的新摄像机矩阵,initCameraMatrix2D得到3D到2D的初始化的摄像机矩阵,matMulDeriv计算矩阵的偏导数,projectPoints将3D坐标投影到图像平面上,reprojectImageTo3D根据一组差异图像重建3D空间,RQDecomp3x3计算3x3矩阵的RQ分解,Rodrigues实现旋转矩阵和旋转向量之间的转换,steroCalibrate校准立体摄像机,steroRectify是对校准过的摄像机计算修正变换,stereoRectifyUncalibrated是对未校准过的摄像机计算修正变换还包括了BM块匹配算法类StereoBM、SGBM块匹配算法类StereoSGBM类
CamShitf算法,即Continuously Apative Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算,将上一帧结果作为下一帧的初始值,迭代下去。基本步骤为:1.选取关键区域2.计算该区域的颜色概率分布--反向投影图3.用MeanShift算法找到下一帧的特征区域4.标记并重复上述步骤该算法的关键就是可以在目标大小发生改变的时候,可以自适应的调整目标区域继续跟踪在进行CamShitf和MeanShift算法的时候,需要输入反向投影图,这就要求有个很重要的预处理过程是计算反向投影图。对应的函数为calcBackProject。所谓反向投影图就是一个概率密度图。calcBackProject的输入通常为目标区域的直方图和待跟踪图像的直方图,输出与待跟踪图像大小相同,每一个像素点表示该点为目标区域的概率。这个点越亮,该点属于物体的概率越大。这样的输入参数太适合做MeanS算法了。关于反向直方图,可以参考一下这篇文章具体代码如下:view plaincalcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);&&calcBackProject(&hue, 1, 0, hist, backproj, &phranges);&&backproj &=&&RotatedRect trackBox = CamShift(backproj, trackWindow,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
这个库中相关的函数有calcOpticalFlowPyrLK、calcOpticalFlowFarneback、estimateRigidTransform、updateMotionHistory、calcMotionGradient、calcGlobalOrientation、segmentMotion、CamShift、meanShift;还有卡尔曼滤波器类KalmanFilter,类内成员函数有构造函数、init、predict、correct。背景单元类BackgroundSubtractor,包括运算符重载,getBackgroundImage,其派生类BackgroundSubtractorMOG和BackgroundSubtractorMOG2,以及只支持Python版本的函数CalcOpticalFlowBM、CalcOpticalFlowHS,c版本的函数cvCalcOpticalFlowLK这些函数每一个背后几乎都是一篇论文,很多都是经典的方法,我才疏识浅,只能边学边总结,先介绍一些我用过的函数,待日后陆续补充calcOpticalPlowPyrLK是利用Lucas-Kanade方法计算图像的光流场
图像的各种变换(cvtColor*+)imgprocimgproc是OpenCV一个比较复杂的lib,我是分开介绍的,之前介绍过了滤波器、直方图、结构分析和形状描述三节,这次介绍一下图像的变换,OpenCV对于图像的变换又可分为几何变换和其他的变换,我这节先介绍一下其他的变换。这部分的函数包括adaptiveThreshold,对图像进行自适应的阈值操作。相应的也有更一般常用的阈值操作函数threshold。这里还是详细介绍一下cvtColor,这个函数是用来进行颜色空间的转换,随着OpenCV版本的升级,对于颜色空间种类的支持也是越来越多。这里汇总一下,把我知道的全部空间列举出来,也许还不完整,希望大家补充。需要先告诉大家的是OpenCV默认的图片通道是BGR。RGB &--& BGR:CV_BGR2BGRA、CV_RGB2BGRA、CV_BGRA2RGBA、CV_BGR2BGRA、CV_BGRA2BGRRGB &--& 5X5:CV_BGR5652RGBA、CV_BGR2RGB555、(以此类推,不一一列举)RGB &---& Gray:CV_RGB2GRAY、CV_GRAY2RGB、CV_RGBA2GRAY、CV_GRAY2RGBARGB &--& CIE XYZ:CV_BGR2XYZ、CV_RGB2XYZ、CV_XYZ2BGR、CV_XYZ2RGBRGB &--& YCrCb(YUV) JPEG:CV_RGB2YCrCb、CV_RGB2YCrCb、CV_YCrCb2BGR、CV_YCrCb2RGB、CV_RGB2YUV(将YCrCb用YUV替代都可以)RGB &--& HSV:CV_BGR2HSV、CV_RGB2HSV、CV_HSV2BGR、CV_HSV2RGBRGB &--& HLS:CV_BGR2HLS、CV_RGB2HLS、CV_HLS2BGR、CV_HLS2RGBRGB &--& CIE L*a*b*:CV_BGR2Lab、CV_RGB2Lab、CV_Lab2BGR、CV_Lab2RGBRGB &--& CIE L*u*v:CV_BGR2Luv、CV_RGB2Luv、CV_Luv2BGR、CV_Luv2RGBRGB &--& Bayer:CV_BayerBG2BGR、CV_BayerGB2BGR、CV_BayerRG2BGR、CV_BayerGR2BGR、CV_BayerBG2RGB、CV_BayerGB2RGB、 CV_BayerRG2RGB、CV_BayerGR2RGB(在CCD和CMOS上常用的Bayer模式)YUV420 &--& RGB:CV_YUV420sp2BGR、CV_YUV420sp2RGB、CV_YUV420i2BGR、CV_YUV420i2RGB还有函数distanceTransform,是用来计算各像素距离最近的零像素距离的。floodFill函数用来用指定颜色填充一个连通部件。inpaint函数用来用附近区域信息重建选中区域,可以对图像里由于传输噪声丢失的块进行重建。integral函数用来获得图像的积分值。给图像添加水印的函数watershed。对图像进行GrabCut算法的grabCut函数(有待研究,不熟悉)。总之,这些变换千奇百怪,不是很系统,常用的还是我先介绍的几个,比如threshold、cvtColor。就这样吧,以后有收获再陆续补充。
contrib为最新贡献但不是很成熟的函数库。作为最新的东西,就更有价值进行庖丁解牛了,我来也。首先介绍一个CvAdaptiveSkinDetector类。该类的功能是自适应的皮肤检测。分析了一下代码,其构造函数的输入参数有两个,samplingDivider样本分类,morphingMethod为变形方法。该类的关键函数为process函数,该函数先将输入图像由RGB转换为HSV空间,Hue的范围是3~33,Intensity(V)的范围为15~250。然后进行必要的腐蚀膨胀,去除噪声,使轮廓更加清晰平滑。具体的使用代码参考sample文件夹中的adaptiveskindetector.cpp最近也在玩手势识别,资料找了很多,基本可以分为静态手势识别和动态手势识别,先弄个简单的静态手势识别给大家看看。基本流程如下:先滤波去噪--&转换到HSV空间--&根据皮肤在HSV空间的分布做出阈值判断,这里用到了inRange函数,然后进行一下形态学的操作,去除噪声干扰,是手的边界更加清晰平滑--&得到的2值图像后用findContours找出手的轮廓,去除伪轮廓后,再用convexHull函数得到凸包络。结果如下:源代码下载位置:,有点贵哦,当时随便设了个值,呵呵
在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数。OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的。这里就介绍一下相关的函数。在绘图函数中都会用到颜色,这里用Scalar结构表示颜色参数。作图相关的函数有circle、clipLine、ellipse、ellipse2Poly、line、rectangle、polylines、类LineIterator。填充相关的函数有fillConvexPoly、fillPoly。显示文字相关的函数有getTextSize、cvInitFont、putText。以上这些函数使用都非常简单方便,我就不过多介绍了。粒子滤波法是指通过寻找一组在状态空间传播的随机样本对概率密度函数进行近似,以样本均值代替积分运算,从而获得状态最小方差分布的过程。对于粒子滤波跟踪方法,这里有一篇很浅显易懂的博客,我分享给大家。他的工作也是参考Rob Hess的程序做的,感谢老外的开源精神,我看了他的程序,我也提出了我的几点改进,作者本身的设想是想做多目标的运动跟踪,但函数接口写的还是有些混乱,以至于最后不能实现(估计是我才疏识浅,没能领会作者的精神),而且用到了gsl数学库,这个库我是不熟悉的,开了一下程序,主要也就只用了里面的随机数的功能,这功能在新版本的OpenCV里已经集成啦,作者用的数据结构还是老版本的结构,好多函数还是作者自己写的,我这里用新版本的数据结构重新写了一遍这个算法,简化跟踪目标为一个。下面介绍一下我的设计流程首先还是将视频转换到HSV颜色空间,我发现很多图像处理的办法都是在该空间下完成的,Rob Hess对HSV颜色空间的特征提取还是很有意思的,他知道色度和饱和度提供的信息和亮度提供的信息分开考虑,做出了他自己的特征直方图。我这里用了新版本的calcHist做的特征直方图,偷了个懒,效果感觉还可以。初始化阶段就是对鼠标选中的目标区域的特征直方图提取,进入搜索阶段,通俗的讲,就是在待搜索区域里放入大量的粒子particle,放入粒子的规则有很多,这里使用的是让粒子的分布为高斯分布,计算每个粒子所在区域的特征直方图,与目标区域特征进行比较,特征接近的粒子的权重大一些,反之权重小一些。通过调整各粒子的权重大小和样本位置来近似实际的概率分布,以样本期望作为系统估计值。然后进行重采样,重新分布粒子的位置。(对于重采样的目的,是为了解决序列重要性采样(SIS)存在的退化现象,即几步迭代之后,许多粒子的权重变得很小,大量的计算浪费在小权值的粒子上。解决退化问题的一般办法就是重采样原理,基本思想就是对后验概率密度再采样,保留复制权重大的粒子,剔除权重小的粒子。程序里感觉只是据粒子的权重的后验概率分布进行一次重新采样,感觉并不是yangyangcv说的那个类似ransac的意思,因为我对代码分析并没有循环放粒子的过程,欢迎大家拍砖)具体的算法流程为我的实际编程步骤大概可以分为如下几步:// step 1: 提取目标区域特征// step 2: 初始化particle(粒子的个数很影响跟踪的速度)// step 3: 求particle的transition(这一步的参数会很影响粒子的变化区域,需要对不同的跟踪对象进行调整参数)// step 4: 求particle区域的特征直方图(特征选取的不合适也很影响结果)// step 5: 特征的比对,更新particle权重(特征比较的方法也是影响结果的因素)// step 6: 归一化粒子权重// step 7: resample根据粒子的权重的后验概率分布重新采样// step 8: 计算粒子的期望,作为跟踪结果再写一下我试验后的心得,我用的是最基本的粒子滤波算法,考虑因素较少,受参数影响很大,而且参数众多,不方便自动调整。对不同的视频跟踪效果差别很大,而且会出现目标丢失的情况。这都是可以改进的。试验代码下载地址为:
OpenCV的发展趋势真是越来越向Linux方向发展,对Windows平台的支持越来越少,2.2版本之后把CvvImage也给删除了,这让人如何开发MFC程序啊,网上搜了好久,基本的办法都是调用之前版本的代码,继续使用CvvImage,这样会导致一个很严重的问题,就是程序里显示的所有的图片都必须是CvvImage类,不能用MFC的图片显示方法,这就需要对代码进行大量的修改,不符合开发的要求。感觉大家的办法都是治标不治本,而且MFC也是快要被日新月异的新技术拍在沙滩上的东西。我总不能永远在控制台下面开发OpenCV应用程序吧。看了一下OpenCV的用户手册,发现它支持跨平台的Qt这个UI开发框架。Qt是诺基亚开发的一个跨平台的C++图形用户界面应用程序框架,我索性也学习一下。Qt的安装我参考的是这篇文章,文章里介绍的方案也是我的开发环境VS2008,想必对于配置OpenCV相当熟练的大牛们,配置Qt肯定也难不倒各位。安装好后,就是进行OpenCV的GUI开发咯从上图中我们可以看出Qt对OpenCV的支持还是很好的,需要用到的开发工具为Qt*GUI,这个GUI可以提供状态栏、工具栏和控制面板。控制面板上面可以制作进度条河按钮等控件(使用trackbar,要确保窗口的参数为NULL;使用buttonbar之前,要先创建一个按钮)。相关的函数有setWindowProperty、getWindowProperty、fontQt、addText、displayOverlay、displayStatusBar、createOpenGLCallback、saveWindowParameters、loadWindowParameters、createButton。由于Qt我也是刚接触,对这些函数的理解和新收获,我会陆续补充在这篇文章里。
这部分内容应该是OpenCV高深精髓的一部分。给OpenCV插上了翅膀,可以使它实现更强大的功能,而不是简单的做一些基本的图像处理。文采太差,就不描绘machine learning的强大了。直接剖析之。大部分的分类器和识别的算法都封装在了c++的类中。有些类有一些共同的基础,都被定义在CvStatModel类中了。那就先介绍这个统计模型类CvStatModel,它是机器学习统计模型的基础类,其包括了构造函数和析构函数,清除内存重置模型状态的clear函数(功能类似析构函数,但可以重用,在析构函数里也调用该函数),模型保存 / 加载XML文件的save / load函数,读写文件和模型的函数write / read,训练模型的函数train,预测样本结果predict函数。普通的贝叶斯分类器CvNormalBayesClassifier,有train和predict函数k近邻算法CvKNearest,有train、find_nearest、get_max_k、get_var_count、get_sample_count、is_regression函数支持向量机SVM相关的有类CvParamGrid用来表示统计参数范围的对数格子,类CvSVMParams、类CvSVM决策树类CvDTreeSplit、CvDTreeNode、CvDTreeParams、CvDTreeTrainData、CvDTreeBoosting算法相关类CvBoostParams、CvBoostTree、CvBoostGradient Boosted Trees(GBT)算法相关类CvGBTreesParams、CvGBTrees随机森林相关算法类CvRTparams、CvRTrees随机树算法的扩展类CvERTrees期望最大EM算法相关类CvEMParams、CvEM神经网络算法相关类CvANN_MLP_TrainParams、CvANN_MLPOpenCV果然够强大,几乎囊括了目前比较流行的全部机器学习方面的经典算法。以上这些牛叉的算法我都好膜拜啊,得下苦功专研了。记得哪位牛人说过algorithm is king,data is queen。有了算法还需要对应的数据类CvMLData、CvTrainTestSplit这部分内容真是博大精深啊,作为初学者,我一直不太敢写这方面的博客,很多算法只知道个皮毛,没有实现过,更不知道其中的奥妙,这里只能先做个介绍,待我日后慢慢丰富内容
一直对MFC对OpenCV的支持不好而耿耿于怀,了解了Qt对OpenCV支持很好,但网上这方面的资料很少。大部分的图形交互的设计都是基于OpenCV2.0之前的数据结构lpImage进行的。最近得到了一本好书《OpenCV 2 Computer Vision Application Programming Cookbook》,下载的链接为,2011年5月出版,全书都是基于OpenCV2.2版本的实现,采用了新的数据结构。我这里强烈建议利用C++开发的朋友们不要再使用老版本的数据结构了,实在影响开发效率。至于大家最熟悉的参考书《learning OpenCV》和《OpenCV教程——基础篇》这两本广为流传的书,}

我要回帖

更多关于 将矩形oabc放在坐标 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信