如果你是用的为VS2010+OPENCV2.3.1,同时学习参考书为《学习OpenCV(中文版)》译者:于仕琪 刘瑞祯出版社:清华大学出版社,则代码不应参考书,而应使用下面链接(OpenCV中文网)http://www.opencv.org.cn/images/2/23/LearningOpenCV_Code.zip
具体看http://www.opencv.org.cn/index.php/%E9%A6%96%E9%A1%B5
**(1)没有找到 tbb_debug.dll
解决方法可以参考下面链接(OpenCV中文网)
http://www.opencv.org.cn/forum/viewtopic.php?p=52223
里面提到三种方法,都可能使用。我的PATH路径设置正确,所以只能用第二种或者第三种解决,我就是将\opencv\build\common\tbb\ia32目录下的tbb.dll复制改名为tbb_debug.dll(win7,vs2010,opencv2.3,运行程序,报错“计算机丢失tbb_debug.dll”)
**(2)VS2010未能正确加载包Visual Studio Class Designer Package
首先,按照提示用,应该用“devenv /log”命令查看生成的activitylog.xml报告。可以在cmd里切换到安装目录下的”……/Common7/IDE“下,然后运行"devenv /log",然后查看生成的activitylog.xml报告。应该看到类似红色标记的错误信息。
解决方法可以使:
方法一:重新正常启动电脑,运行VS,检查是否成功(一般都是因为系统未能及时加载UI控件包)
方法二:在cmd里切换到安装目录下的”……/Common7/IDE“下,然后运行"devenv /resetsettings“(重置),重新启动电脑和VS,检查是否成功
方法三:使用VS安装包内的修复或者卸载重装
**(3)OpenCV 中像素与信道
IplImage* cvCreateImage( CvSize size, int depth, int channels );
功能:创建图像头并分配数据
参数说明:
1) size 图像宽、高.
2) depth 图像元素的位深度,可以是下面的其中之一:
IPL_DEPTH_8U - 无符号8位整型
IPL_DEPTH_8S - 有符号8位整型
IPL_DEPTH_16U - 无符号16位整型
IPL_DEPTH_16S - 有符号16位整型
IPL_DEPTH_32S - 有符号32位整型
IPL_DEPTH_32F - 单精度浮点数
IPL_DEPTH_64F - 双精度浮点数
3)channels:
每个元素(像素)通道.可以是 1, 2, 3 或 4。通道是交叉存取的, 例如通常的彩色图像数据排列是:b0 g0 r0 b1 g1 r1 ... 这个函数也只能创建交叉存取图像.
所谓像素值,即对应像素的数值
所谓的通道,即表示该像素的数值个数
具体可参考下面:
1-灰度图——像素值是该像素点的亮度值
2-二值图,例如RGB565(RGB分别为5位,6位,5位,共16位,两个字节)
3-彩色图像,例如RGB(3通道,RGB,各8位,代表对应三基色色彩值)
4-彩色图像,例如RGBA(前三位同RGB,第四位代表透明度)
**(4)cvGetCaptureProperty函数使用
有时候这个函数单独使用并不能得到正确值,应该先调用一次cvQueryFrame后,再调用cvGetCaptureProperty才会返回正确的数值。这是一个bug,故建议在调用此函数前先调用cvQueryFrame。
**(5)CV_GAUSSIAN_5x5
应注意5乘以5是5x5,而不是5*5,中间为字母xyz中的x
**(6)Debug下点击“调试”或者“开始执行”不能显示图片
解决方法可参考:
http://www.opencv.org.cn/forum/viewtopic.php?p=56721
注意一定要使用绝对路径,且路径里“\”要用“\\”,比如:IplImage* img = cvLoadImage( "D:\\Lena.jpg" );
**(7)结构体与类
我们应发现,OpenCV中,所有的复杂数据结构都是用结构体的形式实现,并且以结构体指针的形式传递。因而OpenCV中没有私有数据!
例如:IplImage* out = cvCreateImage( cvGetSize( in ),in->depth, 1);
其中:返回值为图像类型(结构体)的指针;
cvGetSize的参数也为图像类型(结构体)的指针
利用指针传递数据,是OpenCV的特点,因而我们自己写函数时,返回与参数也应用指针或者数组或者&。
其中:const char*=“字符串”。故而
1)int main( int argc, char** argv ){
IplImage* img_rgb = cvLoadImage( argv[1] );
……
}
并cmd中调用“程序名.exe 参数”(参数1为程序名,参数2、3……为实际参数)
2)int main( ){
IplImage* img_rgb = cvLoadImage("me.jpg") ;
……
}
上面两者功能相同。
**(8)基本数据格式
1)
uchar* ptr;//无符号8位字符型
short* s;//16位短整数
int* i;//32位整数
float* fl;//32位单精度浮点数
double* db;//64位双精度浮点数
2)
type类型:CV_<bit_depth>(S|U|F)C<number_of_chanels>
例如:CV_32FC1,CV_8UC3
N维数组的M维点,存储的方式多种多样,但是最关键的一点,给定点的位置可以由下列公式计算得:
P=(row)*Ncols*Nchannels+(col)*Nchannels+(channel)=前行总个数+本行前总个数+本位置偏移
比如:3*3矩阵,存放CV_32FC3.则有:
x0 y0 z0|x1 y1 z1|x2 y2 z2
x3 y3 z3|x4 y4 z4|x5 y5 z5
x6 y6 z6|x7 y7 z7|x8 y8 z8
则y4在内存中的位置为:
p(y4)=(1)*3*3+(1)*3+(2)=14
3)IplImage中存储RGB,存储顺序为B-G-R
4)cvScalar有四个分量,但是可根据实际选择1,2,3,4,不用的将初始化为0,常见为1(标量),2(向量),3(RGB),4(RGBA),其中,具体代表的意思根据具体情况,比如IplImage中channels顺序为B-R-G,则cvScalar的顺序也就是代表为B-R-G,第四位为0;
**(9)指针与地址
区别参考本程序:
#include <stdio.h>
#include "cv.h"
#include "highgui.h"
void init_0( CvMat* mat ) {
float s = 0.0f;
for( int row=0; row<mat->height; row++ ) {
float* ptr = mat->data.fl + row * mat->step/4;
for( int col=0; col<mat->width; col++ ) {
//*ptr=0;/**ptr表示指针指向的内容,而ptr为指针本身(地址),printf("%d\t",*ptr);输出指针指向的内容,printf("%d\t",ptr);输出指针地址=&(*ptr)*/
//ptr=0;/*指针指向空,等于ptr=NULL,ptr为指针本身(地址);*/
*ptr=0;
printf("%d %d %d\t",ptr,&(*ptr),&ptr);/*由第三个输出可以看出,内存中开辟出一个内存单元,存储指针ptr,故而,&ptr不变,只是其指向(ptr中地址内容)变化而已,%x十六进制格式输出符%o八进制格式输出符%d十进制格式输出符%f浮点型输出符*/
ptr++;
}
printf("\n");
}
};
float sum( CvMat* mat ) {
float s = 0.0f;
for( int row=0; row<mat->height; row++ ) {
float* ptr = mat->data.fl + row * mat->step/4;
for( int col=0; col<mat->width; col++ ) {
s += *ptr++;/* 等于s+=*ptr;ptr++;*/
printf("%f\t",*ptr);
}
printf("\n");
}
return( s );
};
int main(int argc, char** argv)
{
CvMat *mat = cvCreateMat(5,5,CV_32FC1);
init_0(mat);
float element_3_2 = 7.7;
*((float*)CV_MAT_ELEM_PTR( *mat, 3,2) ) = element_3_2;
cvSetReal2D(mat,3,3,0.5000);
float s = sum(mat);
printf("%f\n",s);
return 0;
}
**(10)函数多参数传递原理
首先说一下,windows中,堆栈是从高地址开始压栈的。其次,函数参数是以栈的形式存取的,自右向左压入堆栈。具体可参考下面程序:
#include <iostream>//支持system()
using namespace std;//必须加,支持cout,endl
void fun(int a, ...)
{
int *temp =
&a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp
<< endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d =
4;
fun(4, a, b, c, d);
system("pause");
return
0;
}
输出:
1
2
3
4
省略多参数函数书写规则可参考下面链接:
http://www.cnblogs.com/rainduck/archive/2010/11/10/1873417.html
**(11)非MFC下调试窗口输出函数
随便建一个.H头文件,把下面函数放进去即可
/*我写在dbgprintf.h*/
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h> #define DBG_NUM 4067 void __cdecl DbgPrintf(const char *, ...);//声明,利于编译
void __cdecl dbgprintf(const char *format, ...)
{ char buf[DBG_NUM]; char *bufp = buf;
va_list args;
va_start(args, format); bufp += _vsnprintf(bufp, sizeof buf - 1, format, args);//指针P移动到下一个要写入的部分或者结尾处,应保证最后一个位置必须写‘\0’,故而只写sizeof buf -1
va_end(args); if (bufp<buf)
{
bufp+=DBG_NUM;//越界检查,重新定位,最后一个位置上
OutputDebugStringA("the buff is not enough\n");
} *bufp='\0';
OutputDebugStringA(buf); OutputDebugStringA("\n");//应明白,OutputDebugString(const char *),即参数为静态数组
}
**(12)字符串(组)类型转换
1)char [],const char[],string
string add_to = "hello!";
const char *cfirst = add_to.c_str();
char *copy = new char[strlen(cfirst) + 1];
strcpy(copy, cfirst);
add_to = copy;
delete [] copy;