#
DirectUI 控件,具有简单,可扩展性好等的特点,但是实际开发的时候,遇到复杂的控件,还是喜欢WIN32窗口句柄模式写控件,原因有如下几个
1、消息队列具有线程的安全性。
2、不需要考虑FOCUS,SIZE,MOVE,PAINT,MOUSE,KEY这些框架消息的DISPATCH
3、和已经有的MFC,WIN32代码融合的时间比较少。
Dark Channel Prior去雾的算法,下载了个现成的测试一下,果然效果不错,效果如下。
百度文库里的文档
http://wenku.baidu.com/view/eae99905bed5b9f3f90f1cfd.html
测试图像,
结果图像
宽度W,高度H 的图像,做膨胀操作,如果膨胀的结构元素structure element,大小为kw,kh,那么就需要做W*H*kw*kh次运算,运算量比较大。
根据图像形态学的理论,膨胀满足结合律,即,B和C为结构元素。假设一个结构元素S可以表示为两个结构元素B和C的膨胀,即S=B⊕C,则A⊕S=A⊕(B⊕C)=(A⊕B)⊕C,换言之,用S膨胀A等同于用B先膨胀A,再用C膨胀前面的结果。我们称S能够分解成B和C两个结构元素。结合律很重要,因为计算膨胀所需要的时间正比于结构元素中的非零像素的个数。通过上述推导,分解结构元素,然后再分别用子结构元素进行膨胀操作往往会实现很客观的速度的增长。
同样,腐蚀也可以做结构分解,腐蚀满足公式 ,B和C为结构元素,同样如果一个结构元素S可以表示为两个结构元素B和C的膨胀,即S=B⊕C,那么用S腐蚀A等同于用B先腐蚀A,再用C腐蚀前面的结果。公式推导省略。
图像形态学膨胀和腐蚀介绍,可见
http://en.wikipedia.org/wiki/Erosion_(morphology)
http://en.wikipedia.org/wiki/Dilation_(morphology)
做结构分解后的运算量为W*H*(kw+kh)
代码如下
1#include <cv.h>
2#include <highgui.h>
3#include <stdio.h>
4
5
6int main(int argc, char** argv)
7{
8 if(argc<2) {
9 printf("has no param\n");
10 return 0;
11 }
12
13 IplConvKernel *element1 = cvCreateStructuringElementEx( 1, 25, 0, 0, CV_SHAPE_RECT, 0);
14 IplConvKernel *element2 = cvCreateStructuringElementEx( 16, 1, 0, 0, CV_SHAPE_RECT, 0);
15 IplConvKernel *element3 = cvCreateStructuringElementEx( 16, 25, 0, 0, CV_SHAPE_RECT, 0);
16
17 IplImage* src=cvLoadImage(argv[1],1);
18
19
20 if( src!= NULL)
21 {
22
23 IplImage* img = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
24 cvCvtColor(src,img,CV_BGR2GRAY);
25 cvReleaseImage(&src);
26
27
28 IplImage* tmp = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
29 cvDilate( img, tmp, element1, 1);
30
31 IplImage* dst1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
32 cvDilate( tmp, dst1, element2, 1);
33
34
35 IplImage* dst2 = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
36 cvDilate( img, dst2, element3, 1);
37
38 IplImage* diff = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
39 cvSub(dst2,dst1,tmp,NULL);
40 cvEqualizeHist( tmp, diff);
41 cvReleaseImage(&tmp);
42
43 int noZeroCount=cvCountNonZero(diff);
44 printf("no zerocount %d\n",noZeroCount);
45
46
47 cvNamedWindow("img",CV_WINDOW_AUTOSIZE);
48 cvShowImage("img",img);
49 cvNamedWindow("dst1",CV_WINDOW_AUTOSIZE);
50 cvShowImage("dst1",dst1);
51 cvNamedWindow("dst2",CV_WINDOW_AUTOSIZE);
52 cvShowImage("dst2",dst2);
53 cvNamedWindow("diff",CV_WINDOW_AUTOSIZE);
54 cvShowImage("diff",diff);
55
56
57 cvWaitKey();
58 cvDestroyAllWindows();
59
60
61 cvReleaseImage(&img);
62 cvReleaseImage(&dst1);
63 cvReleaseImage(&dst2);
64 cvReleaseImage(&diff);
65
66 cvReleaseStructuringElement(&element1);
67 cvReleaseStructuringElement(&element2);
68 cvReleaseStructuringElement(&element3);
69
70
71
72
73
74 }
75 else
76 {
77 printf("error,not load\n");
78 }
79 return 0;
80};
81
对N项数据进行判断,生成N项结果,这些结果中有YES,也有NO,采用何种方法,产生最后结果。
0. 努力使结果一致
在判断之前,对N项数据过滤,看是否出现异常,去掉那些因为数据异常而产生的结果,努力使所有结果一致,全是YES或全是NO,当然这就困难了。
1.单值判断
1.1 严格判断,只要有一项结果为NO,就认为最后结果为NO。
1.2 宽松判断,只要有一项结果为YES,就认为最后结果为YES。
2. 对出现的两类结果次数进行比较,选择出现次数多的那项。
3. 根据重要程度来判断。先数值化结果,使YES的值为1,NO的值为0。然后再根据数据的重要程度,定义一些数值,称为重要因子。每项数据产生的数值结果乘以对应的重要因子,再相加这些结果,得出的和值,与给定的阈值相比较,得出最后结果。
SkinLib的代码简单明了,对于想学习和了解UI Skin的原理来说是合适的. 相关链接如下
http://www.cppblog.com/netboy/archive/2009/02/15/73863.html
CSkinDialog 使用Hook,WndProc技术,重载原有绘制消息过程.
CSkinDialog的区域分为客户区域和非客户区域,CSkinDialog的非客户区域又被分为如下几个子区域,
1.左边缘,m_nToLeft为窗口的左边缘长度.
2.右边缘,m_nToRight为右边缘的长度.
3.Caption区域,m_nToTop 为其高度,Caption 区域又可以分为
3.1.(0,0,m_nTopLeft,m_nToTop)
3.2.标题区域 (m_nTopLeft,0,rcWnd.Width()-m_nTopRight,m_nToTop)
3.3.close,max,min 按钮区域
4.下部边缘,m_nToBottom为下部边缘的高度
根据配置文件,读取到相应的Skin,绘制上述Dialog几个子区域.
1.DrawBorder绘制左,右,下部边缘.
2.DrawCaption绘制Caption区域.
Affine ,Perspective变形 资源很多,
可以查看OpenCV
不规则变形
http://paulbourke.net/miscellaneous/imagewarp/
鼠标拉伸改变图像的
http://www.codeproject.com/KB/graphics/localimagewarper.aspx?q=warp
Photoshop液化工具箱中向前变形工具
http://www.cnblogs.com/xiaotie/archive/2009/12/08/1619046.html
如果在.net中一个线程等待另外一个线程的完成,可以使用System.Threading.Thread.Join, 在Win32 下的相应的等效代码
1 WaitForSingleObject(hThread,INFINITE);
2
3 CloseHandle(hThread);
Win32 中CreateThread出来的hThread属于整个Process,线程中的回调函数结束后,不会失效,只有调用者调用CloseHandle,才最后真正的释放系统中Thread 的资源.
如果线程的回调函数已经结束,那么hThread 处于激活状态,WaitForSignleObject 便能获取到当前状态,成功返回;如果没有,WaitForSignleObject 便一直等待线程的回调结束.
如果你想一个线程中等待另外一个线程回调结束的同时,进行消息MSG的分发,或者做其他的事情.例如主UI线程在等待工作线程完成的同时,需要更新UI上的进度条,这时可以让工作线程发送进度消息MSG给主UI线程,主UI线程接受到消息MSG更新UI.可以在主UI线程中使用MsgWaitForMultipleObjects函数达到这一效果,
1 MSG msg;
2
3 BOOL bLoop=TRUE;
4
5 while(bLoop)
6 {
7
8 int nWait=MsgWaitForMultipleObjects(1,&hThread,FALSE,3000,QS_ALLEVENTS);
9 switch(nWait)
10 {
11 case WAIT_TIMEOUT:
12 case WAIT_OBJECT_0+1:
13 {
14 while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
15 TranslateMessage(&msg);
16 DispatchMessage( &msg );
17 }
18 break;
19 }
20
21 case WAIT_OBJECT_0:
22 default:
23 bLoop=FALSE;
24 break;
25 }
26 };
27 CloseHandle(hThread);
28
29
30
代码下载链接如下,
http://www.cppblog.com/Files/mcs51a/blobcounter.rar
代码中涉及到的DIB操作 是8Bit 的二值图像.
CreateThread,是WIN32 最直接创建的thread API函数.但是如果在线程回调(CALLBACK)函数中使用一些标准C的函数,当线程正常退出的时候,即使你释放了所有用户资源,仍然会有资源的泄漏的隐患。主要原因是线程中都需要有额外的资源,来保证一些标准C函数的线程安全,这些资源的创建是在C的标准函数被调用的时候,但是在thread退出的时候,没法通过正常途径释放。
如果在你的回调函数中使用一些标准C函数,最好使用_beginthreadex,_endthreadex替换掉原来的CreateThread, _endthreadex 会释放这些资源,或者AfxBeginThread(里面有调用_beginthreadex,_endthreadex)
具体原因查看《程序员的修养,编译与链接》一书。