# 某島

… : "…アッカリ～ン . .. . " .. .
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 薛怡然 製作

Code::Blocks 10.05 + MinGW 4.4.1 + OpenCV 2.1

*/

#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;		//繪圖線程數（一般會再多出一個）

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;

//單個繪製圖像線程
pair *range = (pair*)param;
for (int i=range->first; isecond; i++) {
for (int j=0; j > param(draw_partition + 1);
//多線程繪製
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;
};

//計算區域複雜度線程
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;
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));
//圖像分區，多線程計算方差
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;
}