《学习opencv》第四章1,2题(第二题详解,最切题)

来源:互联网 发布:有什么好玩的游戏知乎 编辑:程序博客网 时间:2024/06/08 14:05

网上的第二题答案都是在图片上显示文字,我写的时在视频上动态显示文字。

第一题a:

#include "stdafx.h"#include <highgui.h>#include <cv.h>#include <stdlib.h>int _tmain(int argc, _TCHAR* argv[]){char* file_path = "D:/test.avi";CvCapture* capture = 0;capture = cvCreateFileCapture(file_path);//返回指向cvCapture的指针if (capture == NULL){printf("Can't load the video file,quit...");return 1;}IplImage* frame;IplImage* gray_frame;IplImage* canny_frame;while (1){frame = cvQueryFrame(capture);//从cvCapture获取一帧后返回指向它的指针if (!frame)break;gray_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1);cvCvtColor(frame, gray_frame, CV_BGR2GRAY);canny_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1);cvCanny(gray_frame, canny_frame, 30, 100, 3);cvNamedWindow("color", CV_WINDOW_AUTOSIZE);cvNamedWindow("gray", CV_WINDOW_AUTOSIZE);cvNamedWindow("canny", CV_WINDOW_AUTOSIZE);cvShowImage("color", frame);cvShowImage("gray", gray_frame);cvShowImage("canny",canny_frame);char c = cvWaitKey(4);if (c == 27)break;}cvReleaseCapture(&capture);cvReleaseImage(&gray_frame);cvReleaseImage(&canny_frame);//cvReleaseImage(&frame);//这句不可有,因为前面已经释放了CvCapture的结构体cvDestroyAllWindows();system("pause");return 0;}


相关函数:

void cvCanny( const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3 );
image
单通道输入图像.
edges
单通道存储边缘的输出图像
threshold1
第一个阈值
threshold2
第二个阈值
aperture_size
Sobel 算子内核大小 (见 cvSobel).
函数 cvCanny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。threshold1和threshold2 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。


注意事项:cvCanny只接受单通道图像作为输入


第一题b:

因原视频大小过大,结果达不到三个同时显示的效果,因此选择缩放大小至原图1/4。

#include "stdafx.h"#include <highgui.h>#include <cv.h>#include <stdlib.h>IplImage* DoPyDown(IplImage* in, int filter = CV_GAUSSIAN_5x5) {IplImage* image = cvCreateImage(cvSize(in->width / 2, in->height / 2),in->depth,in->nChannels);cvPyrDown(in, image, filter);return image;}int _tmain(int argc, _TCHAR* argv[]){char* file_path = "D:/test.avi";CvCapture* capture = 0;capture = cvCreateFileCapture(file_path);//返回指向cvCapture的指针if (capture == NULL){printf("Can't load the video file,quit...");return 1;}IplImage* temp = cvQueryFrame(capture);IplImage* frame = cvCreateImage(cvSize(temp->width /4, temp->height /4), temp->depth, temp->nChannels);IplImage* gray_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1); IplImage* gray_frame_3 = cvCreateImage(cvGetSize(frame), frame->depth, 3);IplImage* canny_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1);IplImage* canny_frame_3 = cvCreateImage(cvGetSize(frame), frame->depth, 3);IplImage* total_frame = cvCreateImage(cvSize(frame->width * 3, frame->height), frame->depth, frame->nChannels);while (1){frame = cvQueryFrame(capture);if (!frame)break;for (int i = 0; i < 2; i++){frame = DoPyDown(frame);}cvCvtColor(frame, gray_frame, CV_RGB2GRAY);//转换为灰色图cvCvtColor(gray_frame, gray_frame_3, CV_GRAY2RGB);cvCanny(gray_frame, canny_frame, 30, 100, 3);cvCvtColor(canny_frame, canny_frame_3, CV_GRAY2RGB);cvSetImageROI(total_frame, cvRect(0, 0, frame->width, frame->height));cvCopy(frame, total_frame, 0);cvResetImageROI(total_frame);cvSetImageROI(total_frame, cvRect(frame->width, 0, frame->width, frame->height));cvCopy(gray_frame_3, total_frame, 0);cvResetImageROI(total_frame);cvSetImageROI(total_frame, cvRect(frame->width * 2, 0, frame->width, frame->height));cvCopy(canny_frame_3, total_frame, 0);cvResetImageROI(total_frame);CvFont textFont = cvFont(10, 1);cvInitFont(&textFont, CV_FONT_HERSHEY_COMPLEX, 0.5f, 0.5f, 0, 1, 8);cvPutText(total_frame, "frame", cvPoint(10, 20), &textFont, cvScalar(0, 0, 255));cvPutText(total_frame, "gray_frame", cvPoint(frame->width + 10, 20), &textFont, cvScalar(0, 0, 255));cvPutText(total_frame, "canny_fram", cvPoint(frame->width * 2 + 10, 20), &textFont, cvScalar(0, 0, 255));cvShowImage("total", total_frame);char c = cvWaitKey(33);if (c == 27)break;}cvReleaseCapture(&capture);cvReleaseImage(&gray_frame);cvReleaseImage(&gray_frame_3);cvReleaseImage(&canny_frame);cvReleaseImage(&canny_frame_3);cvReleaseImage(&total_frame);system("pause");return 0;}

相关函数:

void cvInitFont( CvFont* font, int font_face, double hscale,double vscale, double shear=0,int thickness=1, int line_type=8 );
font
被初始化的字体结构体。
font_face
字体名称标识符。只是Hershey 字体集( http://sources.isc.org/utils/misc/hershey-font.txt )的一个子集得到支持。
CV_FONT_HERSHEY_SIMPLEX - 正常大小无衬线字体。
CV_FONT_HERSHEY_PLAIN - 小号无衬线字体。
CV_FONT_HERSHEY_DUPLEX - 正常大小无衬线字体。( 比CV_FONT_HERSHEY_SIMPLEX更复杂)
CV_FONT_HERSHEY_COMPLEX - 正常大小有衬线字体。
CV_FONT_HERSHEY_TRIPLEX - 正常大小有衬线字体 ( 比CV_FONT_HERSHEY_COMPLEX更复杂)
CV_FONT_HERSHEY_COMPLEX_SMALL - CV_FONT_HERSHEY_COMPLEX 的小译本。
CV_FONT_HERSHEY_SCRIPT_SIMPLEX - 手写风格字体。
CV_FONT_HERSHEY_SCRIPT_COMPLEX - 比CV_FONT_HERSHEY_SCRIPT_SIMPLEX更复杂。
这个参数能够由一个值和可选择的CV_FONT_ITALIC字体标记合成,就是斜体字。
hscale
字体宽度。如果等于1.0f,字符的宽度是最初的字体宽度。如果等于0.5f,字符的宽度是最初的字体宽度的一半。
vscale
字体高度。如果等于1.0f,字符的高度是最初的字体高度。如果等于0.5f,字符的高度是最初的字体高度的一半。
shear
字体的斜度。当值为0时 ,字符不倾斜;当值为1.0f时,字体倾斜≈45度,等等。厚度让字母着重显示。函数cvLine用于绘制字母。
thickness
字体笔划的粗细程度。
line_type
字体笔划的类型,参见cvLine。

第二题a:

在上一题的基础上改进,只要鼠标点击图片上的任意一点,就会动态显示其像素值,直到下次点击时消失,

用了几个全局变量

#include "stdafx.h"#include <highgui.h>#include <cv.h>#include <stdlib.h>CvFont font;IplImage* g_imag = 0;char text[20] ;int g_x; //上一次点击的像素点int g_y;CvScalar pixel_value;void my_mouse_callback(int event, int x, int y, int flags, void* param){switch (event){case CV_EVENT_LBUTTONDOWN:sprintf(text, "(%d %d %d)", (int)pixel_value.val[0], (int)pixel_value.val[1], (int)pixel_value.val[2]);cvPutText(g_imag, text, cvPoint(x, y), &font, cvScalar(0,0,255));g_x = x;g_y = y;printf("%s \n", text);break;}}IplImage* DoPyDown(IplImage* in, int filter = CV_GAUSSIAN_5x5){IplImage* image = cvCreateImage(cvSize(in->width / 2, in->height / 2),in->depth,in->nChannels);cvPyrDown(in, image, filter);return image;}int _tmain(int argc, _TCHAR* argv[]){cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1.0f, 1.0f, 0, 1, 8);cvNamedWindow("total");cvSetMouseCallback("total", my_mouse_callback,0);char* file_path = "D:/test.avi";CvCapture* capture = 0;capture = cvCreateFileCapture(file_path);//返回指向cvCapture的指针if (capture == NULL){printf("Can't load the video file,quit...");return 1;}IplImage* temp = cvQueryFrame(capture);IplImage* frame = cvCreateImage(cvSize(temp->width /4, temp->height /4), temp->depth, temp->nChannels);IplImage* gray_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1);//转灰度时要定义成单通道IplImage* gray_frame_3 = cvCreateImage(cvGetSize(frame), frame->depth, 3);//三个图合并时则还原成三通道IplImage* canny_frame = cvCreateImage(cvGetSize(frame), frame->depth, 1);IplImage* canny_frame_3 = cvCreateImage(cvGetSize(frame), frame->depth, 3);IplImage* total_frame = cvCreateImage(cvSize(frame->width * 3, frame->height), frame->depth, frame->nChannels);while (1){frame = cvQueryFrame(capture);if (!frame)break;for (int i = 0; i < 2; i++){frame = DoPyDown(frame);}cvCvtColor(frame, gray_frame, CV_RGB2GRAY);cvCvtColor(gray_frame, gray_frame_3, CV_GRAY2RGB);//单通道转三通道cvCanny(gray_frame, canny_frame, 30, 100, 3);cvCvtColor(canny_frame, canny_frame_3, CV_GRAY2RGB);cvSetImageROI(total_frame, cvRect(0, 0, frame->width, frame->height));cvCopy(frame, total_frame, 0);//输入输出要是同样类型cvResetImageROI(total_frame);cvSetImageROI(total_frame, cvRect(frame->width, 0, frame->width, frame->height));cvCopy(gray_frame_3, total_frame, 0);cvResetImageROI(total_frame);cvSetImageROI(total_frame, cvRect(frame->width * 2, 0, frame->width, frame->height));cvCopy(canny_frame_3, total_frame, 0);cvResetImageROI(total_frame);CvFont *textFont = new CvFont();cvInitFont(textFont, CV_FONT_HERSHEY_COMPLEX, 0.5f, 0.5f, 1.0f, 2, 8);cvPutText(total_frame, "frame", cvPoint(10, 20), textFont, cvScalar(0, 0, 255));cvPutText(total_frame, "gray_frame", cvPoint(frame->width + 10, 20), textFont, cvScalar(0, 0, 255));cvPutText(total_frame, "canny_fram", cvPoint(frame->width * 2 + 10, 20), textFont, cvScalar(0, 0, 255));g_imag = total_frame;pixel_value = cvGet2D(g_imag, g_y, g_x);//如果是x,y会出错sprintf(text, "(%d %d %d)", (int)pixel_value.val[0], (int)pixel_value.val[1], (int)pixel_value.val[2]);cvPutText(g_imag, text, cvPoint(g_x, g_y), &font, cvScalar(0, 0, 255));cvShowImage("total", total_frame);delete textFont;char c = cvWaitKey(33);if (c == 27)break;}cvReleaseCapture(&capture);cvReleaseImage(&gray_frame);cvReleaseImage(&gray_frame_3);cvReleaseImage(&canny_frame);cvReleaseImage(&canny_frame_3);cvReleaseImage(&total_frame);system("pause");return 0;}

相关函数:

对cvGet2D()坐标的顺序:
“对于图像中的某一像素点 P(x, y), 在我们正常的坐标系中,x代表其横坐标,y代表其纵坐标,而在opencv的函数 cvGet2D()与cvSet2D() 中,却行不通。cvGet2D() 的函数原型是 : CvScalar  cvGet2D (const CvArr * arr, int idx0, int idx1); 函数返回的是一个CvScalar 容器,其参数中也有两个方向的坐标,但跟我们平常习惯的坐标不一样的是,idx0代表是的行,即高度,对应于我们平常坐标系的y, idx1代表的是列,即宽度,对应于我们平常坐标系的x,cvSet2D() 也类似。所以在使用cvSet2D() 与 cvGet2D() 时,千万要注意坐标的顺序。”

另外,不能靠是否彩色判断是否是RGB图,三通道的也可能是灰色,比如第二张图


三张图的像素值特点(x,y,z)

第一张,原图,三通道,x,y,z可取[0,255]中任一值

第二张,原图转单通道灰度图后,又转为三通道,x=y=z,可取[0,255]中任一值

第三章,单通道灰度图边缘检测之后,转三通道,x=y=z,可取0或者255

结果: