某岛

… : "…アッカリ~ン . .. . " .. .
December 4, 2010

Lab-7,OpenCV …

Nov 29th,去了一下楼上寝室膜拜了一下沙漠君,得到了它们目前的工作进展,是一份高级程序语言的作业 … 啊,当时我就惊了…

xiaodai : “我的这个还不是很好的,Xueyr 的作业在缩放的时侯用了多线程。。。”
xiaodao :”。#啊啊啊啊。。。要怎么在 Xcode 里实现多帧刷屏呢?。。”

//by SHA Mo
//Visual Studio 2010 + OpenCV 2.1


#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

//声明鼠标回调函数
void my_mouse_callback(int event, int x, int y, int flags, void* param);

//图的分辨率
const int IMAGE_SIZE_WID = 640;
const int IMAGE_SIZE_HGT = 480;

//自动缩放图像分割数
const int split_wid = 4;
const int split_hgt = 4;

//迭代次数上界
const int ITERATION_TIME = 200;

//过度动画帧数
const int TRANSITION_IMAGE = 20;

//过度动画帧速
const int TRANSITION_TIME = 1;

//茱莉亚集合参数
double j_re = -0.835;
double j_im = -0.2350;

//图的缩放比
double zoomRatio_WID = 4;
double zoomRatio_HGT = 3;

//函数图象的平移量
double mov_re = -2.5;
double mov_im = -1.5;

//上色控量
const double PI = acos(-1.0);
double ratio_r = 30;		
double ratio_g = 25;
double ratio_b = 20;
double phase_r = 0;			
double phase_g = 0;
double phase_b = 0.25;

//鼠标事件所需量
CvRect box;
bool drawing_box = false;
bool moving = false;
int mov_x;
int mov_y;

//鼠标实时位置
CvPoint mousePoint;

//判断一个复数是否属于Mandelbrot_Set
int mSetTest(double c_re, double c_im) {
	int current_time = 1;
	double z_re = 0;
	double z_im = 0;
	while ( z_re*z_re + z_im*z_im < 4 && current_time < ITERATION_TIME) {
		++current_time;
		double t_re = z_re*z_re - z_im*z_im + c_re;
		z_im = 2*z_re*z_im + c_im;
		z_re = t_re;
	}
	if (current_time == ITERATION_TIME) return 0;
	else return current_time;
}

//判断一个复数是否属于Julia_Set
int jSetTest(double c_re, double c_im) {
	int current_time = 1;
	while ( c_re*c_re + c_im*c_im < 4 && current_time < ITERATION_TIME) {
		++current_time;
		double t_re = c_re*c_re - c_im*c_im + j_re;
		c_im = 2*c_re*c_im + j_im;
		c_re = t_re;
	}
	if (current_time == ITERATION_TIME) return 0;
	else return current_time;
}

//计算像素点的颜色
CvScalar whatColor(int x, int y) {
	//七彩颜色库:红橙黄绿蓝靛紫
	CvScalar colorLib[7] = {{0, 0, 255},{15, 123, 255},{15, 255, 255},{15, 255, 33},{255, 141, 16},{255, 15, 69},{201, 15, 255}};
	CvScalar black = {0, 0, 0};
	CvScalar color;
	int step = jSetTest(mov_re + x/(double)IMAGE_SIZE_WID*zoomRatio_WID, mov_im + y/(double)IMAGE_SIZE_HGT*zoomRatio_HGT);
	if (step) {
		//不属于分型集合
		//color = colorLib[(step + 5) % 7];
		color.val[0] = 127.5 - 127.5 * cos(step / ratio_b + phase_b * PI);
		color.val[1] = 127.5 - 127.5 * cos(step / ratio_g + phase_g * PI);
		color.val[2] = 127.5 - 127.5 * cos(step / ratio_r + phase_r * PI);
	}
	else {
		//属于分型集合
		color = black;
	}
	return color;
}

//绘制选定框
void draw_box( IplImage* img, CvRect rect ) {
	cvRectangle (
		img,
		cvPoint(box.x, box.y),
		cvPoint(box.x+box.width, box.y+box.height),
		cvScalar(0x00, 0xff, 0x00)
		);
}

//绘制图像
void draw( IplImage* image ) {
	for (int i = 0; i < IMAGE_SIZE_WID; ++i)
		for (int j = 0; j < IMAGE_SIZE_HGT; ++j) {
			cvSet2D(image, j, i, whatColor(i, j));
		}
}

//自定义可以越界的取色函数
CvScalar my_cvGet2D(IplImage* image, int x, int y)
{
	//越界返回黑色
	if (x<0 || y<0 || x>=IMAGE_SIZE_WID || y>=IMAGE_SIZE_HGT) return cvScalar(0x00, 0x00, 0x00);
	return cvGet2D(image, y, x);
}

//拷贝图像矩形区域(允许越界,越界部分填黑,ROI实现)
IplImage* my_cvCloneImageRect(IplImage* src, CvRect rect) {
	IplImage *dst = cvCreateImage(cvSize(rect.width, rect.height), src->depth, src->nChannels);
	cvSetZero(dst);

	//计算src的ROI矩形
	CvRect src_rect;
	src_rect.x = max(0, rect.x);
	src_rect.y = max(0, rect.y);
	src_rect.width = min(src->width, rect.x + rect.width) - src_rect.x;
	src_rect.height = min(src->height, rect.y + rect.height) - src_rect.y;
	if (src_rect.width <= 0 || src_rect.height <= 0) {
		src_rect.width = 0;
		src_rect.height = 0;
	}

	//计算dst的ROI矩形
	CvRect dst_rect;
	dst_rect.x = max(0, -rect.x);
	dst_rect.y = max(0, -rect.y);
	dst_rect.width = min(rect.width, -rect.x + src->width) - dst_rect.x;
	dst_rect.height = min(rect.height, -rect.y + src->height) - dst_rect.y;	

	if (dst_rect.width <= 0 || dst_rect.height <= 0) {
		dst_rect.width = 0;
		dst_rect.height = 0;
	}
	if (src_rect.width!=0 && src_rect.height!=0 && dst_rect.width!=0 && dst_rect.height!=0) {
		cvSetImageROI(src, src_rect);
		cvSetImageROI(dst, dst_rect);
		cvResize(src, dst);
		cvResetImageROI(src);
		cvResetImageROI(dst);
	}
	return dst;
}

//显示过度效果
IplImage* show_transition(IplImage* image, CvRect &box) {
	
	IplImage* tmp = cvCloneImage( image );
	for (int k = 1; k <= TRANSITION_IMAGE; ++k) {

		//计算分步缩放的临时选定框
		double tmp_x = box.x * (double)k/TRANSITION_IMAGE;
		double tmp_y = box.y * (double)k/TRANSITION_IMAGE;
		double tmp_width = IMAGE_SIZE_WID - (IMAGE_SIZE_WID - box.x - box.width) * (double)k/TRANSITION_IMAGE - tmp_x;
		double tmp_height = IMAGE_SIZE_HGT - (IMAGE_SIZE_HGT - box.y - box.height) * (double)k/TRANSITION_IMAGE - tmp_y;

		CvRect tmp_box = cvRect(tmp_x, tmp_y, tmp_width, tmp_height);
		cvResize(my_cvCloneImageRect(image, tmp_box), tmp);
		cvShowImage("HelloOpenCV", tmp);
		cvWaitKey( TRANSITION_TIME );
	}
	return tmp;
}

//移动缩放图像(增加动态动画效果)
void move_zoom_image(IplImage* image, CvRect &box, bool transition = 1) {
	IplImage* current_image = image;

	//显示过度效果
	if (transition) {
		current_image = show_transition( image, box );
	}

	//改变函数图象的平移量
	mov_re += (double)box.x/IMAGE_SIZE_WID*zoomRatio_WID;
	mov_im += (double)box.y/IMAGE_SIZE_HGT*zoomRatio_HGT;

	//改变图的缩放比
	zoomRatio_WID *= (double)box.width/IMAGE_SIZE_WID;
	zoomRatio_HGT *= (double)box.height/IMAGE_SIZE_HGT;

	//刷新图像
	draw( image );
}

//灰度图,开在函数内部会栈溢出
int grey_level[IMAGE_SIZE_WID][IMAGE_SIZE_HGT];
//评估图像复杂度(多算子加权:信息熵、反差[灰度矩阵求法]、边缘比率)
double image_rect_complexity( IplImage* image, CvRect rect ) {
	//各灰度像素数
	int grey_level_count[256] = {};

	//灰度总量
	int grey_level_num = rect.width * rect.height;

	//灰度共生矩阵
	int GLCM[256][256] = {};

	//抽取图像灰度信息
	for (int i = rect.x; i < rect.x + rect.width; ++i)
		for (int j = rect.y; j < rect.y + rect.height; ++j) {
			grey_level[i][j]  = ((uchar*)(image->imageData + j*image->widthStep))[i*image->nChannels + 0];
			grey_level[i][j] += ((uchar*)(image->imageData + j*image->widthStep))[i*image->nChannels + 1];
			grey_level[i][j] += ((uchar*)(image->imageData + j*image->widthStep))[i*image->nChannels + 2];
			grey_level[i][j] /= 3;
			++grey_level_count[ grey_level[i][j] ];
		}

	//计算灰度共生矩阵(△x=1,△y=1)和 边缘像素数
	int edge_pixel = 0;
	for (int i = rect.x; i < rect.x + rect.width - 1; ++i)
		for (int j = rect.y; j < rect.y + rect.height - 1; ++j) {
			++GLCM[grey_level[i][j]][grey_level[i+1][j+1]];
			if (grey_level[i][j] != grey_level[i+1][j+1]) ++edge_pixel;
		}


	//计算信息熵
	double inf_entropy = 0;
	for (int i = 0; i < 256; ++i) if (grey_level_count[i] != 0) {
		inf_entropy -= (double)grey_level_count[i]/grey_level_num * log((double)grey_level_count[i]/grey_level_num);
	}

	//计算反差
	double contrast = 0;
	for (int i = 0; i < 256; ++i)
		for (int j = 0; j < 256; ++j) if (GLCM[i][j] != 0)
			contrast = (double)GLCM[i][j]/grey_level_num * (i - j) * (i - j);

	//边缘比率
	double edge_ratio = edge_pixel / grey_level_num;

	//返回加权图像复杂度
	return contrast/2 + inf_entropy + edge_ratio;
}

//自动缩放
void auto_zoom( IplImage* image ) {
	double max_complexity = 0;
	CvRect max_complex_rect;
	for (int i = 0; i < split_wid; ++i)
		for (int j = 0; j < split_hgt; ++j) {
			double tmp_complexity = image_rect_complexity( image, 
				cvRect(	i*(IMAGE_SIZE_WID/split_wid), 
						j*(IMAGE_SIZE_HGT/split_hgt),
						IMAGE_SIZE_WID/split_wid,
						IMAGE_SIZE_HGT/split_hgt ) );
			if (tmp_complexity > max_complexity) {
				max_complex_rect = cvRect(	
					i*(IMAGE_SIZE_WID/split_wid), 
					j*(IMAGE_SIZE_HGT/split_hgt),
					IMAGE_SIZE_WID/split_wid,
					IMAGE_SIZE_HGT/split_hgt );
				max_complexity = tmp_complexity;
			}
		}
	move_zoom_image( image, max_complex_rect );
}

int main( int argc, char* argv[] ) {
	//初始化选定框变量
	box = cvRect(-1, -1, 0, 0);

	//创建图像
	IplImage* pImg = cvCreateImage (/*size*/cvSize (IMAGE_SIZE_WID, IMAGE_SIZE_HGT), /*depth*/IPL_DEPTH_8U, /*nChannels*/3);
	cvSetZero(pImg);
	IplImage* temp = cvCloneImage( pImg );

	//创建窗口
	cvNamedWindow (/*name of the window*/"HelloOpenCV", 1);

	//标志鼠标事件
	cvSetMouseCallback("HelloOpenCV", my_mouse_callback, (void*) pImg);

	//初始化图像
	draw( pImg );

	//反复获取用户交互信息并处理
	while ( 1 ) {
		CvFont font;
		double hScale = 1.0;
		double vScale = 1.0;
		int lineWidth = 1;
		cvCopyImage( pImg, temp );

		//实时绘制选定框
		if ( drawing_box ) draw_box( temp, box );

		//按住右键时拖动画面
		if ( moving ) {
			CvRect tmp_box = cvRect(mov_x - mousePoint.x , mov_y - mousePoint.y, pImg->width, pImg->height);
			cvResize(my_cvCloneImageRect(pImg, tmp_box), temp);
		}

		//实时显示鼠标位置对应的复数坐标系的坐标
		cvInitFont(&font, CV_FONT_HERSHEY_DUPLEX, hScale, vScale, 0, lineWidth);

		char x_coord[10];
		itoa((int)mousePoint.x, x_coord, 10);
		char y_coord[10];
		itoa((int)mousePoint.y, y_coord, 10);
		cvPutText(temp, strcat(strcat(x_coord, ","), y_coord), mousePoint, &font, cvScalar(0x00, 0x00, 0xff));
		cvShowImage( "HelloOpenCV", temp);

		//输入ESC后退出
		int key_num = cvWaitKey( 20 );
		if ( key_num == 27 ) break;
		else if ( key_num == 'r') {
			CvRect normal =  cvRect(0, 0, pImg->width, (int)(pImg->height / ((zoomRatio_HGT/zoomRatio_WID)/((double)IMAGE_SIZE_HGT/IMAGE_SIZE_WID))));
			move_zoom_image( pImg, normal );
			//zoomRatio_HGT = zoomRatio_WID * IMAGE_SIZE_HGT / IMAGE_SIZE_WID;
			//draw( pImg );
		}
		else if ( key_num == 'c') auto_zoom( pImg );
	}
	
	//关闭窗口、释放图像
	cvReleaseImage( &pImg );
	cvReleaseImage( &temp );
	cvDestroyWindow( "HelloOpenCV" );
	return 0;
}

//定义鼠标事件回调函数
void my_mouse_callback(int event, int x, int y, int flags, void* param) {
	
	IplImage* image = (IplImage*) param;
	switch ( event ) {

	//鼠标拖动
	case CV_EVENT_MOUSEMOVE :

		mousePoint = cvPoint(x, y);
		//左键拖动时实时维护选定框
		if (flags & CV_EVENT_FLAG_LBUTTON) {
			drawing_box = true;
			if ( drawing_box ) {
				box.width = x - box.x;
				box.height = y - box.y;
			}
		}
		else if (flags & CV_EVENT_FLAG_RBUTTON) {
			moving = true;
		}
	break;

	//左键按下
	case CV_EVENT_LBUTTONDOWN: 
		drawing_box = false;
		box = cvRect(x,y,0,0);
		break;

	//左键抬起
	case CV_EVENT_LBUTTONUP:
		if (drawing_box) {
			drawing_box = false;
			//确保选定框长宽正值
			if (box.width < 0) {
				box.x += box.width;
				box.width *= -1;
			}
			if (box.height < 0) {
				box.y += box.height;
				box.height *= -1;
			}
			move_zoom_image(image, box);
		}
		else {
			box = cvRect(x-IMAGE_SIZE_WID/2, y-IMAGE_SIZE_HGT/2, IMAGE_SIZE_WID, IMAGE_SIZE_HGT);
			move_zoom_image(image, box);
		}
		break;

	//右键按下
	case CV_EVENT_RBUTTONDOWN:
		moving = false;
		mov_x = x;
		mov_y = y;
		break;

	//右键放开
	case CV_EVENT_RBUTTONUP: 
		if (moving) {
			moving = false;
			box = cvRect(mov_x - x, mov_y - y, IMAGE_SIZE_WID, IMAGE_SIZE_HGT);
			move_zoom_image(image, box, 0);
		}
		else {
			box = cvRect(-IMAGE_SIZE_WID/2, -IMAGE_SIZE_HGT/2, IMAGE_SIZE_WID*2, IMAGE_SIZE_HGT*2);
			move_zoom_image(image, box);
		}
		break;
	}
}
/*

1100300627 薛怡然 制作

环境  Visual Studio 2010 + OpenCV 2.1
      Code::Blocks 10.05 + MinGW 4.4.1 + OpenCV 2.1

本机编译、运行通过

实现功能:Task 2 ~ Task 6

附加功能:右键拖动平移、多重采样抗锯齿、动画缩放、朱利亚集、多线程绘图、多线程搜索复杂区域、用户配置文件等

*/

#include 		//C++
#include 
#include 
#include 		//STL
#include 
#include 
#include 		//C
#include 
#include 
#include 	//WIN32
#include 			//OpenCV
#include 

#define LIMIT_SQUARE 4		//迭代阈值(2)的平方

//以下全局变量可通过设置函数读取 config.ini 进行更改

char name_m[] = "Mandelbrot";	//窗口名
char name_j[] = "Julia";
char* window_name = name_m;

double julia_set = false;		//分形种类:false:曼得波罗集 true:朱利亚集

//为统一接口,定义:
//曼得波罗集:		z[n+1] = z[n]^2 + c
//朱利亚集:		c[n+1] = c[n]^2 + j_c

double j_c_re = -0.726895347709114071439;	//朱利亚集中 j_c 的实部
double j_c_im = 0.188887129043845954792;	//朱利亚集中 j_c 的虚部

bool ssaa = true;			//4x多重采样抗锯齿开关
int max_iteration = 300;	//最大迭代次数
int img_width = 800;		//图像宽度
int img_height = 600;		//图像高度
int animation = 20;			//动画缩放效果步数
int max_zoom = 10;			//自动缩放最大次数
int zoom_partition = 4;		//自动缩放画面每轴分区数
int zoom_delay = 3000;		//自动缩放延迟(毫秒)
double ctr_re = -0.5, ctr_im = 0;	//图像中心复平面坐标
double img_left = -2;				//图像左边缘复平面实轴坐标

int draw_partition = 8;		//绘图线程数(一般会再多出一个)
int draw_thread = 0;		//绘图线程返回计数
int beauty_thread = 0;      //区域复杂度线程返回计数

IplImage *img, *tmp;		//img:主体图像 tmp:用于动态显示的临时图像
CvRect box;					//临时线框
bool drawing_box = false;	//绘制线框状态
CvPoint move_from, move_to;	//右键平移范围
bool moving = false;		//右键平移状态

double pi = acos(-1.0);		//上色三角函数用 π
double ratio_r = 30;		//上色三角函数自变量系数(倒数)
double ratio_g = 25;
double ratio_b = 20;
double phase_r = 0;			//上色三角函数初相 / π
double phase_g = 0;
double phase_b = 0.25;

using namespace std;
using namespace cv;

//测试C是否属于M_Set
int xMSetTest(double c_re, double c_im) {
	double z_re = 0, z_im = 0, temp;
    int step = 0;
    while (z_re*z_re + z_im*z_im < LIMIT_SQUARE && step != max_iteration) {
		temp = z_re * z_re - z_im * z_im;
		z_im = 2 * z_re * z_im + c_im;
		z_re = temp + c_re;
        step++;
    }
    if (z_re*z_re + z_im*z_im < LIMIT_SQUARE && step == max_iteration)
		return 0;
    else return step;
}

//测试C是否属于J_SET
int xJSetTest(double c_re, double c_im) {
	double temp;
	int step = 0;
	while (c_re*c_re + c_im*c_im < LIMIT_SQUARE && step != max_iteration) {
		temp = c_re * c_re - c_im * c_im;
		c_im = 2 * c_re * c_im + j_c_im;
		c_re = temp + j_c_re;
        step++;
    }
	if (c_re*c_re + c_im*c_im < LIMIT_SQUARE && step == max_iteration)
		return 0;
	else return step;
}

//测试函数指针,用于给 M_SET 与 J_SET 测试提供同样接口
int (*xSetTest)(double c_re, double c_im) = xMSetTest;

//整型绝对值
inline int xAbs(int x) {
	return (x > 0) ? x : -x;
}

//像素坐标转换至复平面坐标(实轴)
inline double xRe(double x) {
	return ctr_re + (2 * x - img_width)
		* (ctr_re - img_left) / img_width;
}

//像素坐标转换至复平面坐标(虚轴)
inline double xIm(double y) {
	return ctr_im - (2 * y - img_height)
		* (ctr_re - img_left) / img_width;
}

//拷贝图像矩形区域(允许越界,越界部分填黑)
IplImage* xCloneImageOver(IplImage* src, CvRect rect) {
	IplImage *dst = cvCreateImage(cvSize(rect.width, rect.height), src->depth, src->nChannels);
	cvSetZero(dst);
	CvRect src_range = rect;
	CvRect dst_range = cvRect(0, 0, rect.width, rect.height);
	//检查四侧越界,适当缩小复制范围
	if (src_range.x < 0) {
		src_range.width += src_range.x;
		dst_range.width += src_range.x;
		dst_range.x -= src_range.x;
		src_range.x = 0;
	}
	if (src_range.y < 0) {
		src_range.height += src_range.y;
		dst_range.height += src_range.y;
		dst_range.y -= src_range.y;
		src_range.y = 0;
	}
	if (src_range.x + src_range.width > src->width) {
		int diff = src_range.x + src_range.width - src->width;
		src_range.width -= diff;
		dst_range.width -= diff;
	}
	if (src_range.y + src_range.height > src->height) {
		int diff = src_range.y + src_range.height - src->height;
		src_range.height -= diff;
		dst_range.height -= diff;
	}
	//检查完全越界状态
	if (src_range.height <= 0 || src_range.width <= 0) return dst;
	//复制图像内容
	for (int i = 0; i < src_range.height; i++) {
		char* src_ptr = src->imageData + (src_range.y + i) * src->widthStep +
			src_range.x * (src->depth / 8) * src->nChannels;
		char* dst_ptr = dst->imageData + (dst_range.y + i) * dst->widthStep +
			dst_range.x * (src->depth / 8) * src->nChannels;
		memcpy(dst_ptr, src_ptr, src_range.width * (src->depth / 8) * src->nChannels);
	}
	return dst;
}

//定义像素颜色 & 4xAA
CvScalar xColorAA(double x, double y) {
	double result[4];
	CvScalar color = cvScalar(0);
	result[0] = xSetTest(xRe(x - 0.125), xIm(y - 0.25));
	result[1] = xSetTest(xRe(x + 0.25), xIm(y - 0.125));
	result[2] = xSetTest(xRe(x + 0.125), xIm(y + 0.25));
	result[3] = xSetTest(xRe(x - 0.25), xIm(y + 0.125));
	for (int i=0; i<4; i++) {
		if (result[i]) {
			color.val[0] += 127.5 - 127.5 * cos(result[i] / ratio_b + phase_b * pi);
			color.val[1] += 127.5 - 127.5 * cos(result[i] / ratio_g + phase_g * pi);
			color.val[2] += 127.5 - 127.5 * cos(result[i] / ratio_r + phase_r * pi);
		} else {
			color.val[0] += 0;
			color.val[1] += 0;
			color.val[2] += 0;
		}
	}
	color.val[0] /= 4;
	color.val[1] /= 4;
	color.val[2] /= 4;
	return color;
}

//定义像素颜色 & noAA
CvScalar xColorNoAA(double x, double y) {
	double result = xSetTest(xRe(x),xIm(y));
	CvScalar color;
	if (result) {
		color.val[0] = 127.5 - 127.5 * cos(result / ratio_b + phase_b * pi);
		color.val[1] = 127.5 - 127.5 * cos(result / ratio_g + phase_g * pi);
		color.val[2] = 127.5 - 127.5 * cos(result / ratio_r + phase_r * pi);
	} else {
		color.val[0] = 0;
		color.val[1] = 0;
		color.val[2] = 0;
	}
	return color;
}

//定义像素颜色函数指针,用于给 xColorAA 和 xColorNoAA 提供同样接口
CvScalar (*xColor)(double x, double y) = xColorNoAA;

//单个绘制图像线程
DWORD WINAPI xDrawThread(LPVOID param) {
	pair *range = (pair*)param;
	for (int i=range->first; isecond; i++) {
		for (int j=0; j > param(draw_partition + 1);
	draw_thread = 0;
	//多线程绘制
	for (int i=0; i 10000) x = 0;
		if (y > 10000) y = 0;
		if (flags & CV_EVENT_FLAG_LBUTTON) { //左键拖动
			drawing_box = true;
			box.width = x - box.x;
			box.height = y - box.y;
			if (xAbs(box.width) * img_height > xAbs(box.height) * img_width) {
				box.height = ((box.height > 0) ? 1 : -1) *
					xAbs(box.width) * img_height / img_width;
			} else {
				box.width = ((box.width > 0) ? 1 : -1) *
					xAbs(box.height) * img_width / img_height;
			}
		} else if (flags & CV_EVENT_FLAG_RBUTTON) { //右键拖动
			moving = true;
			move_to.x = 2 * move_from.x - x;
			move_to.y = 2 * move_from.y - y;
		}
		break;
	case CV_EVENT_LBUTTONDOWN: //左键按下
		drawing_box = false;
		box = cvRect(x,y,0,0);
		break;
	case CV_EVENT_LBUTTONUP: //左键放开
		if (drawing_box && xAbs(box.width) > 2) {
			drawing_box = false;
			if (box.width < 0) {
				box.x += box.width;
				box.width *= -1;
			}
			if (box.height < 0) {
				box.y += box.height;
				box.height *= -1;
			}
			xZoom(box);
		} else {
			drawing_box = false;
			xZoom(cvRect(x - img_width / 2, y - img_height / 2,
				img_width, img_height));
		}
		break;
	case CV_EVENT_RBUTTONDOWN: //右键按下
		moving = false;
		move_from.x = x;
		move_from.y = y;
		break;
	case CV_EVENT_RBUTTONUP: //右键放开
		if (moving) {
			moving = false;
			double t_ctr_re = xRe(move_to.x - move_from.x + img_width / 2.0);
			double t_ctr_im = xIm(move_to.y - move_from.y + img_height / 2.0);
			img_left = xRe(move_to.x - move_from.x);
			ctr_re = t_ctr_re;
			ctr_im = t_ctr_im;
			xReDraw();
		} else {
			xZoom(cvRect(x, y, 0, 0), 0.5);
		}
		break;
	}
}

//计算区域复杂度线程参数
struct BeautyParam {
	double result;
	CvPoint begin, end;
};

//计算区域复杂度线程
DWORD WINAPI xBeautyThread(LPVOID thread_param) {
	BeautyParam *param = (BeautyParam*)thread_param;
	int real_num = (param->end.x - param->begin.x) * (param->end.y - param->begin.y);
	int color_num = real_num;
	CvScalar average = cvScalar(0);
	param->result = 0;
	uchar *ptr;
	//计算平均值,黑色不计
	for (int i=param->begin.y; iend.y; i++) {
		ptr = (uchar*)(img->imageData + i * img->widthStep);
		for (int j=param->begin.x; jend.x; j++) {
			if (ptr[3 * j] || ptr[3 * j + 1] || ptr[3 * j + 2]) {
				average.val[0] += ptr[3 * j];
				average.val[1] += ptr[3 * j + 1];
				average.val[2] += ptr[3 * j + 2];
			} else {
				color_num--;
			}
		}
	}
	if (color_num) {
		average.val[0] /= color_num;
		average.val[1] /= color_num;
		average.val[2] /= color_num;
	}
	//计算方差,黑色不计入平方和,但计入分母数
	for (int i=param->begin.y; iend.y; i++) {
		ptr = (uchar*)(img->imageData + i * img->widthStep);
		for (int j=param->begin.x; jend.x; j++) {
			if (ptr[3 * j] || ptr[3 * j + 1] || ptr[3 * j + 2]) {
				param->result += (ptr[3 * j] - average.val[0]) *
					(ptr[3 * j] - average.val[0]);
				param->result += (ptr[3 * j + 1] - average.val[1]) *
					(ptr[3 * j + 1] - average.val[1]);
				param->result += (ptr[3 * j + 2] - average.val[2]) *
					(ptr[3 * j + 2] - average.val[2]);
			}
		}
	}
	param->result /= real_num;
	beauty_thread--;
	return 0;
}

//查找复杂区域
int xFindBeauty(){
	vector param(zoom_partition * zoom_partition);
	int unit_x = img_width / zoom_partition;
	int unit_y = img_height / zoom_partition;
	CvRNG seed = cvRNG(time(0));
	//图像分区,多线程计算方差
	beauty_thread = 0;
	for (int i=0; i param[max].result) max = i;
	}
	return max;
};

//自动查找复杂区域并缩放
void xAutoZoom() {
	int zoom_to;
	int unit_x = img_width / zoom_partition;
	int unit_y = img_height / zoom_partition;
	CvRect auto_box;
	cout << "Auto Zoom" << endl;
	for (int i=0; i= 40 && img_height >= 40){
		cvCopyImage(img, tmp);
		cvRectangle(tmp, cvPoint(20, 20),
			cvPoint(img_width - 20, img_height - 20),
			cvScalar(0xff,0xff,0xff), 2);
		cvRectangle(tmp, cvPoint(20, 20),
			cvPoint(img_width - 20, img_height - 20),
			cvScalar(0xff,0x00,0x00));
		cvShowImage(window_name, tmp);
		cvWaitKey(1000);
		cvShowImage(window_name, img);
	}
	cout << "Manual Operate" << endl;
}

//循环绘制图像并接收用户输入
void xLoop() {
	box = cvRect(-1,-1,0,0);
	int key = 0;
	xReDraw();
	for (;;) {
		if (drawing_box) { //左键选定矩形区域时
			cvCopyImage(img,tmp);
			cvRectangle(tmp,
				cvPoint(box.x, box.y),
				cvPoint(box.x + box.width, box.y + box.height),
				cvScalar(0xff,0xff,0xff), 2);
			cvRectangle(tmp,
				cvPoint(box.x, box.y),
				cvPoint(box.x + box.width, box.y + box.height),
				cvScalar(0xff,0x00,0x00));
			cvShowImage(window_name,tmp);
		} else if (moving) { //右键拖动平移图像时
			IplImage *move = xCloneImageOver(img, cvRect(
				move_to.x - move_from.x,
				move_to.y - move_from.y,
				img_width,
				img_height));
			cvShowImage(window_name, move);
			cvReleaseImage(&move);
		} else { //空闲时
			cvShowImage(window_name, img);
		}
		cvSetMouseCallback(window_name, xOnMouse);
		if (drawing_box || moving) key = cvWaitKey(15);
		else key = cvWaitKey(100);
		if (key == 27) return;
		if (key == 'a') xAutoZoom();
	}
}

//读取设置文件
void xSetting() {
	ifstream fi("config.ini");
	string cmd;
	double val;
	//随机生成图像颜色
	CvRNG seed = cvRNG(time(0));
	ratio_r = cvRandReal(&seed) * 50 + 10;
	ratio_g = cvRandReal(&seed) * 50 + 10;
	ratio_b = cvRandReal(&seed) * 50 + 10;
	phase_r = cvRandReal(&seed) * 2 * pi;
	phase_g = cvRandReal(&seed) * 2 * pi;
	phase_b = cvRandReal(&seed) * 2 * pi;
	//读取用户设置
	while (fi >> cmd >> val) {
		if (cmd == "julia_set" && val == 1) {
			julia_set = true;
			window_name = name_j;
			xSetTest = xJSetTest;
			ctr_re = 0;
			ctr_im = 0;
			img_left = -1.5;
		}
		else if (cmd == "ssaa" || cmd == "4xAA") ssaa = (val != 0);
		else if (cmd == "max_iteration") max_iteration = (int)val;
		else if (cmd == "img_width" && val > 0) img_width = (int)val;
		else if (cmd == "img_height" && val > 0) img_height = (int)val;
		else if (cmd == "animation" && val >= 1) animation = (int)val;
		else if (cmd == "max_zoom" && val >= 1) max_zoom = (int)val;
		else if (cmd == "zoom_partition" && val >= 1) zoom_partition = (int)val;
		else if (cmd == "zoom_delay" && val >= 1) zoom_delay = (int)val;
		else if (cmd == "draw_partition" && val >= 1) draw_partition = (int)val;
		else if (cmd == "ctr_re") ctr_re = val;
		else if (cmd == "ctr_im") ctr_im = val;
		else if (cmd == "img_left") img_left = val;
		else if (cmd == "ratio_r" && val != 0) ratio_r = val;
		else if (cmd == "ratio_g" && val != 0) ratio_g = val;
		else if (cmd == "ratio_b" && val != 0) ratio_b = val;
		else if (cmd == "phase_r") phase_r = val;
		else if (cmd == "phase_r") phase_r = val;
		else if (cmd == "phase_r") phase_r = val;
		else if (cmd == "j_c_re") j_c_re = val;
		else if (cmd == "j_c_im") j_c_im = val;
	}
	//检查复平面设置
	if (img_left > ctr_re) img_left = 2 * ctr_re - img_left;
	//设置计算像素颜色函数指针
	if (ssaa) xColor = xColorAA;
}

//创建和删除图像
int main() {
	xSetting();
	cout << "Use mouse to zoom in, zoom out, or move the image." << endl;
	cout << "Press A in the image window to enter Auto Zoom mode." << endl << endl;
	img = cvCreateImage(cvSize(img_width, img_height),/*depth*/8,/*nChannels*/3);
	tmp = cvCloneImage(img);
	xLoop();
	cvReleaseImage(&img);
	cvReleaseImage(&tmp);
	return 0;
}

参考资料

OpenCV 中文站
M67 Pascal 的绘图程序..