影象處理經典演算法及OpenCV程式
基於opencv的use攝像頭視訊採集程式
準備工作:你得把opencv庫裝到電腦上,並把各種標頭檔案,原始檔,lib庫都連到vc上,然後設定一下系統環境變數,這裡這方面就不說了,好像我前面的文章有說過,不懂也可百度一下。
建立一個基於WIN32控制檯的工程CameraUSB,在新建一個c++元檔案,寫程式碼:
#include "cxcore.h" #include "cvcam.h" #include "windows.h" #include "highgui.h"
void callback(IplImage* image); int main() { int ncams=cvcamGetCamerasCount( );//返回可以訪問的攝像頭數目 HWND MyWin; // 設定系統屬性 cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE); //選擇第一個攝像頭 //camera cvcamSetProperty(0, CVCAM_PROP_RENDER, CVCAMTRUE); //We'll render stream // 在本例中 // 假設建立一個視窗,並且視窗的ID是在變數 MyWin 中定義 // MyWin 是視窗 HWND 的型別 MyWin=(HWND)cvGetWindowHandle("CameraUSB window"); cvcamSetProperty(0,CVCAM_PROP_WINDOW,&MyWin); // Selects a window for //video rendering //回撥函式將處理每一幀 cvcamSetProperty(0,CVCAM_PROP_CALLBACK,callback); cvcamInit( ); cvcamStart( ); // 現在程式開始工作 cvWaitKey(0); cvcamStop( ); cvcamExit( ); return 0; }
// 在影象中畫蘭色水平線 void callback(IplImage* image) { IplImage* image1 = image; int i,j; assert (image); for(i=0; i<image1->height; i+=10) { for(j=(image1->widthStep)*i; j<(image1->widthStep)*(i+1); j+=image1->nChannels) { image1->imageData[j] = (char)255; image1->imageData[j+1] = 0; image1->imageData[j+2] = 0; } } }
嘿嘿,就這麼簡單就完事了。
不懂可留言問
實現功能:同時採集兩路USB攝像頭資料,並顯示,具有圖片儲存功能(點選左鍵儲存圖片,並暫停視訊;右鍵繼續視訊)。步驟就不說了,很簡單,直接放程式碼了:
#include <cvcam.h> #include <cv.h> #include <highgui.h> #include "stdio.h" #include <windows.h>
void StereoCallback(IplImage *frame1,IplImage *frame2); void onMouse1(int Event,int x,int y,int flags,void *param); void onMouse2(int Event,int x,int y,int flags,void *param);
IplImage *image1,*image2;
char *strleft[4]={"left1.bmp","left2.bmp","left3.bmp","left4.bmp"}; char *strright[4]={"right1.bmp","right2.bmp","right3.bmp","right4.bmp"};
void main() { HWND CaptureWindow1=0; //不賦值也行 HWND CaptureWindow2=0;
//int ncams=cvcamGetCamerasCount(); //獲取攝像頭的個數,在這裡可有可無 //用對話方塊的形式來選取攝像頭 int *CameraNumber; int nSelected = cvcamSelectCamera(&CameraNumber);
/* //灰色影象 image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1); image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1); */
//彩色影象 image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3); image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3);
//初始化兩個攝像頭 cvNamedWindow("cvcam1 Window",1); CaptureWindow1=(HWND)cvGetWindowHandle("cvcam1 Window"); cvcamSetProperty(CameraNumber[0], CVCAM_PROP_ENABLE, CVCAMTRUE); cvcamSetProperty(CameraNumber[0], CVCAM_PROP_RENDER, CVCAMTRUE); cvcamSetProperty(CameraNumber[0], CVCAM_PROP_WINDOW, &CaptureWindow1); // cvSetMouseCallback("cvcam1 Window",onMouse1,0); cvNamedWindow("cvcam2 Window",1); CaptureWindow2=(HWND)cvGetWindowHandle("cvcam2 Window"); cvcamSetProperty(CameraNumber[1], CVCAM_PROP_ENABLE, CVCAMTRUE); cvcamSetProperty(CameraNumber[1], CVCAM_PROP_RENDER, CVCAMTRUE); cvcamSetProperty(CameraNumber[1], CVCAM_PROP_WINDOW, &CaptureWindow2); // cvSetMouseCallback("cvcam2 Window",onMouse2,0);
//讓兩個攝像頭同步 cvcamSetProperty(CameraNumber[0],CVCAM_STEREO_CALLBACK,(void*)&StereoCallback);
//啟動程式 cvcamInit(); cvcamStart(); cvSetMouseCallback("cvcam1 Window",onMouse1,0); cvSetMouseCallback("cvcam2 Window",onMouse2,0); cvWaitKey(0);
cvcamStop(); free(CameraNumber); cvcamExit(); cvDestroyWindow("cvcam1 Window"); cvDestroyWindow("cvcam2 Window"); }
void StereoCallback(IplImage* frame1,IplImage *frame2) {
/* //把影象轉換成灰度圖並儲存到image中 cvCvtColor(frame1,image1,CV_RGB2GRAY); cvCvtColor(frame2,image2,CV_RGB2GRAY); */
//拷貝影象到全域性變數image中 該函式這樣用存在問題 // cvCopy(frame1,image1); // cvCopy(frame2,image2); image1=cvCloneImage(frame1); image2=cvCloneImage(frame2); //對擷取的影象翻轉 cvFlip(image1,image1,0); cvFlip(image2,image2,0);
} void onMouse1(int Event,int x,int y,int flags,void *param) { static int num=0; if(Event==CV_EVENT_LBUTTONDOWN) { if(num==4)num=0;//只是固定定義了儲存4張圖片,為了不讓程式非法而設定的復原 cvcamPause(); //影象儲存 cvSaveImage(strleft[num],image1); // cvSaveImage(strright[num],image2); // cvSaveImage("left.bmp",image1); // cvSaveImage("right.bmp",image2);
} if(Event==CV_EVENT_RBUTTONDOWN) { cvcamResume(); num++; } }
void onMouse2(int Event,int x,int y,int flags,void *param) { static int num=0; if(Event==CV_EVENT_LBUTTONDOWN) { if(num==4)num=0;//只是固定定義了儲存4張圖片,為了不讓程式非法而設定的復原 cvcamPause(); //影象儲存 // cvSaveImage(strleft[num],image1); cvSaveImage(strright[num],image2); // cvSaveImage("left.bmp",image1); // cvSaveImage("right.bmp",image2);
} if(Event==CV_EVENT_RBUTTONDOWN) { cvcamResume(); num++; } }
這個程式是基於opencv的,連線庫就不說了,直接建立一個基於win32的控制檯程式,寫程式碼就OK了。
/* 程式名:drawing..c 功能:展示OpenCV的影象繪製功能 */ #include "cv.h" #include "highgui.h" #include <stdlib.h> #include <stdio.h> #define NUMBER 100 #define DELAY 5 char wndname[] = "Drawing Demo";
CvScalar random_color(CvRNG* rng) //函式 cvRNG 初始化隨機數生成器並返回其狀態,RNG 隨機數生成器 { int icolor = cvRandInt(rng); //函式 cvRandInt 返回均勻分佈的隨機 32-bit 無符號整型值並更新 RNG 狀態 return CV_RGB(icolor&255, (icolor>>8)&255, (icolor>>16)&255); //建立 一個色彩值 }
int main( int argc, char** argv ) { int line_type = CV_AA; // change it to 8 to see non-antialiased graphics int i; CvPoint pt1,pt2; //基於二維整形座標軸的點 double angle; CvSize sz; //矩形框大小,以畫素為精度 CvPoint ptt[6]; CvPoint* pt[2]; int arr[2]; CvFont font; CvRNG rng; int width = 1000, height = 700; int width3 = width*3, height3 = height*3; CvSize text_size; int ymin = 0; // Load the source image IplImage* image = cvCreateImage( cvSize(width,height), 8, 3 ); IplImage* image2;
// Create a window cvNamedWindow(wndname, 1 ); cvZero( image ); //#define cvZero cvSetZero void cvSetZero( CvArr* arr ); arr 要被清空陣列 cvShowImage(wndname,image);
rng = cvRNG((unsigned)-1); pt[0] = &(ptt[0]); pt[1] = &(ptt[3]);
arr[0] = 3; arr[1] = 3;
for (i = 0; i< NUMBER; i++) { pt1.x=cvRandInt(&rng) % width3 - width; pt1.y=cvRandInt(&rng) % height3 - height; pt2.x=cvRandInt(&rng) % width3 - width; pt2.y=cvRandInt(&rng) % height3 - height;
cvLine( image, pt1, pt2, random_color(&rng), cvRandInt(&rng)%10, line_type, 0 );//繪製連線兩個點的線段 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 0; i< NUMBER; i++) { pt1.x=cvRandInt(&rng) % width3 - width; pt1.y=cvRandInt(&rng) % height3 - height; pt2.x=cvRandInt(&rng) % width3 - width; pt2.y=cvRandInt(&rng) % height3 - height;
cvRectangle( image,pt1, pt2, random_color(&rng), cvRandInt(&rng)%10-1, line_type, 0 );//繪製簡單、指定粗細或者帶填充的 矩形 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 0; i< NUMBER; i++) { pt1.x=cvRandInt(&rng) % width3 - width; pt1.y=cvRandInt(&rng) % height3 - height; sz.width =cvRandInt(&rng)%200; sz.height=cvRandInt(&rng)%200; angle = (cvRandInt(&rng)%1000)*0.180;
cvEllipse( image, pt1, sz, angle, angle - 100, angle + 200, random_color(&rng), cvRandInt(&rng)%10-1, line_type, 0 );//函式cvEllipse用來繪製或者填充一個簡單的橢圓弧或橢圓扇形 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 0; i< NUMBER; i++) { pt[0][0].x=cvRandInt(&rng) % width3 - width; pt[0][0].y=cvRandInt(&rng) % height3 - height; pt[0][1].x=cvRandInt(&rng) % width3 - width; pt[0][1].y=cvRandInt(&rng) % height3 - height; pt[0][2].x=cvRandInt(&rng) % width3 - width; pt[0][2].y=cvRandInt(&rng) % height3 - height; pt[1][0].x=cvRandInt(&rng) % width3 - width; pt[1][0].y=cvRandInt(&rng) % height3 - height; pt[1][1].x=cvRandInt(&rng) % width3 - width; pt[1][1].y=cvRandInt(&rng) % height3 - height; pt[1][2].x=cvRandInt(&rng) % width3 - width; pt[1][2].y=cvRandInt(&rng) % height3 - height;
cvPolyLine( image, pt, arr, 2, 1, random_color(&rng), cvRandInt(&rng)%10, line_type, 0 );//函式cvPolyLine 繪製一個簡單的或多樣的多角曲線 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 0; i< NUMBER; i++) { pt[0][0].x=cvRandInt(&rng) % width3 - width; pt[0][0].y=cvRandInt(&rng) % height3 - height; pt[0][1].x=cvRandInt(&rng) % width3 - width; pt[0][1].y=cvRandInt(&rng) % height3 - height; pt[0][2].x=cvRandInt(&rng) % width3 - width; pt[0][2].y=cvRandInt(&rng) % height3 - height; pt[1][0].x=cvRandInt(&rng) % width3 - width; pt[1][0].y=cvRandInt(&rng) % height3 - height; pt[1][1].x=cvRandInt(&rng) % width3 - width; pt[1][1].y=cvRandInt(&rng) % height3 - height; pt[1][2].x=cvRandInt(&rng) % width3 - width; pt[1][2].y=cvRandInt(&rng) % height3 - height;
cvFillPoly( image, pt, arr, 2, random_color(&rng), line_type, 0 );//函式cvFillPoly用於一個單獨被多變形輪廓所限定的區域內進行填充 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 0; i< NUMBER; i++) { pt1.x=cvRandInt(&rng) % width3 - width; pt1.y=cvRandInt(&rng) % height3 - height;
cvCircle( image, pt1, cvRandInt(&rng)%300, random_color(&rng), cvRandInt(&rng)%10-1, line_type, 0 );//函式cvCircle繪製或填充一個給定圓心和半徑的圓 cvShowImage(wndname,image); cvWaitKey(DELAY); }
for (i = 1; i< NUMBER; i++) { pt1.x=cvRandInt(&rng) % width3 - width; pt1.y=cvRandInt(&rng) % height3 - height;
cvInitFont( &font, cvRandInt(&rng) % 8, (cvRandInt(&rng)%100)*0.05+0.1, (cvRandInt(&rng)%100)*0.05+0.1, (cvRandInt(&rng)%5)*0.1, cvRound(cvRandInt(&rng)%10), line_type );//字型結構初始化。函式 cvRound, cvFloor, cvCeil 用一種舍入方法將輸入浮點數轉換成整數。 cvRound 返回和引數最接近的整數值
cvPutText( image, "Northeast Petroleum University!", pt1, &font, random_color(&rng));//在影象中加入文字 cvShowImage(wndname,image); cvWaitKey(DELAY); }
cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX, 3, 3, 0.0, 5, line_type );
cvGetTextSize( "Opencv forever!", &font, &text_size, &ymin );//設定字串文字的寬度和高度
pt1.x = (width - text_size.width)/2; pt1.y = (height + text_size.height)/2; image2 = cvCloneImage(image);
for( i = 0; i < 255; i++ ) { cvSubS( image2, cvScalarAll(i), image, 0 );//函式 cvSubS 從原陣列的每個元素中減去一個數量 cvPutText( image, "shentuhongfeng forever!", pt1, &font, CV_RGB(255,i,i)); cvShowImage(wndname,image); cvWaitKey(DELAY); }
// Wait for a key stroke; the same function arranges events processing cvWaitKey(0); cvReleaseImage(&image); cvReleaseImage(&image2); cvDestroyWindow(wndname);
return 0; }
效果圖:太帥了
黑的變白了,白的變黑了
原始碼:
#include<stdio.h> #include<math.h> #include<cv.h> #include<highgui.h>
int main(int argc,char* argv[]) { IplImage* img=0; int height,width,step,channels; UCHAR* data; int i,j,k; if(argc<2) { printf("Usage:InvImage<image-file-name>\n\7"); exit(0); } img=cvLoadImage(argv[1]); if(!img) { printf("Could not load image file:%s\n",argv[1]); exit(0); } height=img->height; width=img->width; step=img->widthStep; channels=img->nChannels; data=(UCHAR*)img->imageData; printf("Processing a%d*%d image with %d channels\n",height,width,channels); cvNamedWindow("mainWin",CV_WINDOW_AUTOSIZE); cvMoveWindow("mainWin",100,100);
for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++) data[i*step+j*channels+k]=255-data[i*step+j*channels+k]; cvShowImage("mainWin",img); cvWaitKey(0); cvReleaseImage(&img); return 0; }
首先要準備一張圖片,和幾個txt文件,把txt文件的副檔名改成一個你要把圖片轉換成的格式
我用的原始圖片是jpg的,txt改成bmp的
使用時,執行-cmd-cd 轉到你的目錄- Convert.exe 1.jpg 2.bmp 執行就能把影象1.jpg轉換成2.bmp了
原始碼如下:
/* 程式名:convert.c 功能:影象格式的轉換 */ #include <cv.h> #include <highgui.h> #include <stdio.h> int main( int argc, char** argv ) { IplImage* src; // -1: the loaded image will be loaded as is (with number of channels depends on the file). if(argc != 3) { printf("CONV: Image format convertion, support JPG,BMP,TIF,PNG,PPM\n"); printf("Usage: conv srcImage dstImage\n"); return 0; } if( ( strstr(argv[1],".jpg")==NULL && strstr(argv[1],".bmp")==NULL && strstr(argv[1],".tif")==NULL && strstr(argv[1],".png")==NULL && strstr(argv[1],".ppm")==NULL ) || ( strstr(argv[2],".jpg")==NULL && strstr(argv[2],".bmp")==NULL && strstr(argv[2],".tif")==NULL && strstr(argv[2],".png")==NULL && strstr(argv[2],".ppm")==NULL )) //strstr(a, b)的用法是不是在a陣列內檢視是否有b陣列。。。沒有則輸出NULL { printf("WARNING: CONV only support JPG,BMP,TIF,PPM,TGA and PPM\n"); } else { if( (src=cvLoadImage(argv[1], -1))!= 0 ) { cvSaveImage( argv[2], src); cvReleaseImage(&src); printf("\n Convert successfully.\n"); } else { printf("\n*** Read or write image fails *** \n"); } } return 0; }
發現了個小問題:
原來的jpg影象只有102KB轉換成bmp後變成549KB ,在執行程式把這個bmp轉成jpg又只有81KB。這真是汗死我了
從攝像頭或者AVI檔案中得到視訊流,對視訊流進行邊緣檢測
/* 程式名稱:laplace.c 功能:從攝像頭或者AVI檔案中得到視訊流,對視訊流進行邊緣檢測,並輸出結果。 */ #include "cv.h" #include "highgui.h" #include <ctype.h> #include <stdio.h>
int main( int argc, char** argv ) { IplImage* laplace = 0; IplImage* colorlaplace = 0; IplImage* planes[3] = { 0, 0, 0 }; // 多個影象面 CvCapture* capture = 0; // 下面的語句說明在命令列執行程式時,如果指定AVI檔案,那麼處理從 // AVI檔案讀取的視訊流,如果不指定輸入變數,那麼處理從攝像頭獲取 // 的視訊流 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] );
if( !capture ) { fprintf(stderr,"Could not initialize capturing...\n"); return -1; } cvNamedWindow( "Laplacian", 0 );
// 迴圈捕捉,直到使用者按鍵跳出迴圈體 for(;;) { IplImage* frame = 0; int i;
frame = cvQueryFrame( capture ); if( !frame ) break;
if( !laplace ) { for( i = 0; i < 3; i++ ) planes[i] = cvCreateImage( cvSize(frame->width,frame->height), 8, 1 ); laplace = cvCreateImage( cvSize(frame->width,frame->height), IPL_DEPTH_16S, 1 ); colorlaplace = cvCreateImage( cvSize(frame->width,frame->height), 8, 3 ); } cvCvtPixToPlane( frame, planes[0], planes[1], planes[2], 0 ); for( i = 0; i < 3; i++ ) { cvLaplace( planes[i], laplace, 3 ); // 3: aperture_size cvConvertScaleAbs( laplace, planes[i], 1, 0 ); // planes[] = ABS(laplace) } cvCvtPlaneToPix( planes[0], planes[1], planes[2], 0, colorlaplace ); colorlaplace->origin = frame->origin;
cvShowImage("Laplacian", colorlaplace );
if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow("Laplacian"); return 0; }
#include "cv.h" #include "highgui.h"
char wndname[] = "Edge"; char tbarname[] = "Threshold"; int edge_thresh = 1;
IplImage *image = 0, *cedge = 0, *gray = 0, *edge = 0;
// 定義跟蹤條的 callback 函式 void on_trackbar(int h) { cvSmooth( gray, edge, CV_BLUR, 3, 3, 0 ); cvNot( gray, edge );
// 對灰度影象進行邊緣檢測 cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 3); cvZero( cedge ); // copy edge points cvCopy( image, cedge, edge ); // 顯示影象 cvShowImage(wndname, cedge); }
int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)"fruits.jpg"; if( (image = cvLoadImage( filename, 1)) == 0 ) return -1;
// Create the output image cedge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3);
// 將彩色影象轉換為灰度影象 gray = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1); edge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1); cvCvtColor(image, gray, CV_BGR2GRAY);
// Create a window cvNamedWindow(wndname, 1);
// create a toolbar cvCreateTrackbar(tbarname, wndname, &edge_thresh, 100, on_trackbar);
// Show the image on_trackbar(1);
// Wait for a key stroke; the same function arranges events processing cvWaitKey(0); cvReleaseImage(&image); cvReleaseImage(&gray); cvReleaseImage(&edge); cvDestroyWindow(wndname);
return 0; }
/*******程式碼中的函式說明 1、cvSmooth,其函式宣告為: cvSmooth( const void* srcarr, void* dstarr, int smoothtype,int param1, int param2, double param3 ) cvSmooth函式的作用是對圖象做各種方法的圖象平滑。其中,srcarr為輸入圖象;dstarr為輸出圖象; param1為平滑操作的第一個引數;param2為平滑操作的第二個引數(如果param2值為0,則表示它被設為param1); param3是對應高斯引數的標準差。 引數smoothtype是圖象平滑的方法選擇,主要的平滑方法有以下五種: CV_BLUR_NO_SCALE:簡單不帶尺度變換的模糊,即對每個象素在 param1×param2領域求和。 CV_BLUR:對每個象素在param1×param2鄰域求和並做尺度變換 1/(param1?param2)。 CV_GAUSSIAN:對影象進行核大小為param1×param2的高斯卷積。 CV_MEDIAN:對影象進行核大小為param1×param1 的中值濾波(鄰域必須是方的)。 CV_BILATERAL:雙向濾波,應用雙向 3x3 濾波,彩色設定為param1,空間設定為param2。
2、void cvNot(const CvArr* src,CvArr* dst); 函式cvNot()會將src中的每一個元素的每一位取反,然後把結果賦給dst。 因此,一個值為0x00的8點陣圖像將被對映到0xff,而值為0x83的影象將被對映到0x7c。
3、void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 ); 採用 Canny 演算法做邊緣檢測 image 輸入影象 edges 輸出的邊緣影象 threshold1 第一個閾值 threshold2 第二個閾值 aperture_size Sobel 運算元核心大小
4、void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL ); 在使用這個函式之前,你必須用cvCreateImage()一類的函式先開一段記憶體,然後傳遞給dst。 cvCopy會把src中的資料複製到dst的記憶體中。
5、cvCreateTrackbar 建立trackbar並將它新增到指定的視窗。 int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change ); trackbar_name 被建立的trackbar名字。 window_name 視窗名字,這個視窗將為被建立trackbar的父物件。 value 整數指標,它的值將反映滑塊的位置。這個變數指定建立時的滑塊位置。 count 滑塊位置的最大值。最小值一直是0。 on_change 每次滑塊位置被改變的時候,被呼叫函式的指標。這個函式應該被宣告為void Foo(int); 如果沒有回撥函式,這個值可以設為NULL。 函式cvCreateTrackbar用指定的名字和範圍來建立trackbar(滑塊或者範圍控制),指定與trackbar位置同步的變數, 並且指定當trackbar位置被改變的時候呼叫的回撥函式。被建立的trackbar顯示在指定視窗的頂端。 */
角點檢測
原始圖:
處理後圖:
原始碼:
#include <stdio.h> #include "cv.h" #include "highgui.h" #define max_corners 100
int main( int argc, char** argv ) { int cornerCount=max_corners; CvPoint2D32f corners[max_corners]; IplImage *srcImage = 0, *grayImage = 0, *corners1 = 0, *corners2 = 0; int i; CvScalar color = CV_RGB(255,0,0); char* filename = argc == 2 ? argv[1] : (char*)"pic3.png"; // 注意相對路徑 cvNamedWindow( "image", 1 ); // create HighGUI window with name "image" //Load the image to be processed srcImage = cvLoadImage(filename, 1); grayImage = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1); //copy the source image to copy image after converting the format cvCvtColor(srcImage, grayImage, CV_BGR2GRAY); //create empty images of same size as the copied images corners1= cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_32F, 1); corners2= cvCreateImage(cvGetSize(srcImage),IPL_DEPTH_32F, 1); cvGoodFeaturesToTrack (grayImage, corners1, corners2, corners, &cornerCount, 0.05, 5, 0, 3, // block size 0, // not use harris 0.4 ); printf("num corners found: %d\n", cornerCount); // draw circles at each corner location in the gray image and //print out a list the corners if(cornerCount>0) { for (i=0; i<cornerCount; i++) { cvCircle(srcImage, cvPoint((int)(corners[i].x), (int)(corners[i].y)), 6, color, 2, CV_AA, 0); } } cvShowImage( "image", srcImage ); cvReleaseImage(&srcImage); cvReleaseImage(&grayImage); cvReleaseImage(&corners1); cvReleaseImage(&corners2); cvWaitKey(0); // wait for key. The function has return 0; }
友情連結一下,這是別人寫的:
#include "cv.h" #include "highgui.h" #include "math.h" int main( int argc, char** argv ) { IplImage* src; /* the first command line parameter must be image file name */ if( argc==2 && (src = cvLoadImage(argv[1], -1))!=0) { IplImage* dst = cvCloneImage( src ); int delta = 1; int angle = 0; int opt = 1; // 1: 旋轉加縮放 // 0: 僅僅旋轉 double factor; cvNamedWindow( "src", 1 ); cvShowImage( "src", src );
for(;;) { float m[6]; // Matrix m looks like: // // [ m0 m1 m2 ] ===> [ A11 A12 b1 ] // [ m3 m4 m5 ] [ A21 A22 b2 ] // CvMat M = cvMat( 2, 3, CV_32F, m ); int w = src->width; int h = src->height; if(opt) // 旋轉加縮放 factor = (cos(angle*CV_PI/180.) + 1.05)*2; else // 僅僅旋轉 factor = 1; m[0] = (float)(factor*cos(-angle*2*CV_PI/180.)); m[1] = (float)(factor*sin(-angle*2*CV_PI/180.)); m[3] = -m[1]; m[4] = m[0]; // 將旋轉中心移至影象中間 m[2] = w*0.5f; m[5] = h*0.5f; // dst(x,y) = A * src(x,y) + b cvGetQuadrangleSubPix( src, dst, &M);//提取象素四邊形,使用子象素精度 cvNamedWindow( "dst", 1 ); cvShowImage( "dst", dst ); if( cvWaitKey(5) == 27 ) break; angle =(int) (angle + delta) % 360; } // for-loop } return 0; }
原始圖:
效果圖:(正變換)
反變換:
正反變換隻是函式中一個引數的不同,具體看你所需要的應用。
cvLogPolar函式可以用來模擬人類的中央視覺(foveal vision),並可以用於物體跟蹤方面的尺度及旋轉不變模板的快速匹配。
原始碼:
#include <cv.h> #include <highgui.h>
int main(int argc, char** argv) { IplImage* src;
if( argc == 2 && (src=cvLoadImage(argv[1],1)) != 0 ) { IplImage* dst = cvCreateImage( cvSize(256,256), 8, 3 ); IplImage* src2 = cvCreateImage( cvGetSize(src), 8, 3 ); cvLogPolar( src, dst, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ); cvLogPolar( dst, src2, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP ); cvNamedWindow( "log-polar", 1 ); cvShowImage( "log-polar", dst ); cvNamedWindow( "inverse log-polar", 1 ); cvShowImage( "inverse log-polar", src2 ); cvWaitKey(); } return 0; }
效果圖:(什麼東東長這麼醜啊,汗)
#include <cv.h> #include <highgui.h> #include <stdlib.h> #include <stdio.h>
IplImage* src = 0; IplImage* dst = 0;
IplConvKernel* element = 0; int element_shape = CV_SHAPE_RECT;
//the address of variable which receives trackbar position update int max_iters = 10; int open_close_pos = 0; int erode_dilate_pos = 0;
// callback function for open/close trackbar void OpenClose(int pos) { int n = open_close_pos - max_iters; int an = n > 0 ? n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); cvDilate(dst,dst,element,1); } else { cvDilate(src,dst,element,1); cvErode(dst,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Open/Close",dst); }
// callback function for erode/dilate trackbar void ErodeDilate(int pos) { int n = erode_dilate_pos - max_iters; int an = n > 0 ? n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); } else { cvDilate(src,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Erode/Dilate",dst); }
int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)"baboon.jpg"; if( (src = cvLoadImage(filename,1)) == 0 ) return -1;
printf( "Hot keys: \n" "\tESC - quit the program\n" "\tr - use rectangle structuring element\n" "\te - use elliptic structuring element\n" "\tc - use cross-shaped structuring element\n" "\tENTER - loop through all the options\n" );
dst = cvCloneImage(src);
//create windows for output images cvNamedWindow("Open/Close",1); cvNamedWindow("Erode/Dilate",1);
open_close_pos = erode_dilate_pos = max_iters; cvCreateTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,OpenClose); cvCreateTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate);
for(;;) { int c; OpenClose(open_close_pos); ErodeDilate(erode_dilate_pos); c = cvWaitKey(0);
if( (char)c == 27 ) break; if( (char)c == 'e' ) element_shape = CV_SHAPE_ELLIPSE; else if( (char)c == 'r' ) element_shape = CV_SHAPE_RECT; else if( (char)c == 'c' ) element_shape = CV_SHAPE_CROSS; else if( (char)c == '\n' ) element_shape = (element_shape + 1) % 3; }
//release images cvReleaseImage(&src); cvReleaseImage(&dst);
//destroy windows cvDestroyWindow("Open/Close"); cvDestroyWindow("Erode/Dilate");
return 0; }
函式cvSmooth實現各種方法的圖形平滑。
一般來說,影象平滑主要是為了消除噪聲。影象的常見噪聲主要有加性噪聲、乘性噪聲和量化噪聲等。由於影象的能量主要集在低頻部分,而噪聲所在頻段主要在高頻段,因此通常都是採用低通濾波的方法消除噪聲。
函式cvFilter2D對影象做卷積運算。
對影象進行線性濾波,支援替換方式操作。當核運算部份超出輸入影象時,邊界外面的畫素值等於離它最近的影象畫素值。
效果圖:
原始碼:
// Filtering for Image with variaty filtering kernel // // CV_PREWITT_3x3_V A gradient filter (vertical Prewitt operator). // -1 0 1 // -1 0 1 // -1 0 1 // CV_PREWITT_3x3_H A gradient filter (horizontal Prewitt operator). // 1 1 1 // 0 0 0 // -1 -1 -1 // CV_SOBEL_3x3_V A gradient filter (vertical Sobel operator). // -1 0 1 // -2 0 2 // -1 0 1 // CV_SOBEL_3x3_H A gradient filter (horizontal Sobel operator). // 1 2 1 // 0 0 0 // -1 -2 -1 // CV_LAPLACIAN_3x3 A 3x3 Laplacian highpass filter. // -1 -1 -1 // -1 8 -1 // -1 -1 -1 // CV_LAPLACIAN_3x3 A 3x3 Laplacian highpass filter (another kernel) // This kernel is similar with function: cvLaplace with aperture_size=1 // 0 1 0 // 1 -4 1 // 0 1 0 注:直接用cvFilter2D得到的結果與用cvLaplace得到的結果 // 略有不同 // CV_LAPLACIAN_5x5 A 5x5 Laplacian highpass filter. // -1 -3 -4 -3 -1 // -3 0 6 0 -3 // -4 6 20 6 -4 // -3 0 6 0 -3 // -1 -3 -4 -3 -1 // CV_GAUSSIAN_3x3 A 3x3 Gaussian lowpass filter. // This filter uses the kernel A/16,where // 1 2 1 // A = 2 4 2 // 1 2 1 // These filter coefficients correspond to a 2-dimensional Gaussian // distribution with standard deviation 0.85. // // CV_GAUSSIAN_5x5 A 5x5 Gaussian lowpass filter. // This filter uses the kernel A/571,where // 2 7 12 7 2 // 7 31 52 31 7 // A = 12 52 127 52 12 // 7 31 52 31 7 // 2 7 12 7 2
#include <cv.h> #include <highgui.h> #include <stdio.h>
int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0, *dst2 = 0; /*float k[9] = { 0, 1, 0, 1,-4, 1, 0, 1, 0}; */ float k[9] = { 1.f/16, 2.f/16, 1.f/16, 2.f/16, 4.f/16, 2.f/16, 1.f/16, 2.f/16, 1.f/16}; // 這裡高斯核濾波器歸一化 CvMat Km; //cvInitMatHeader( &Km, 3, 3, CV_32FC1, k, CV_AUTOSTEP ); Km = cvMat( 3, 3, CV_32F, k );
// 0: force to gray image src = cvLoadImage("lena.jpg", 0); dst = cvCloneImage( src );
cvNamedWindow("src", 0); cvShowImage("src",src); cvNamedWindow("filtering", 0); cvFilter2D( src, dst, &Km, cvPoint(-1,-1)); cvShowImage("filtering",dst); cvWaitKey(0);
cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; }
效果圖:
原始碼:
#include "cv.h" #include "highgui.h" #include <stdio.h> #include <stdlib.h>
IplImage* color_img0; IplImage* mask; IplImage* color_img; IplImage* gray_img0 = NULL; IplImage* gray_img = NULL; int ffill_case = 1; int lo_diff = 20, up_diff = 20; int connectivity = 4; int is_color = 1; int is_mask = 0; int new_mask_val = 255;
void on_mouse( int event, int x, int y, int flags, void* param ) { if( !color_img ) return;
switch( event ) { case CV_EVENT_LBUTTONDOWN: { CvPoint seed = cvPoint(x,y); int lo = ffill_case == 0 ? 0 : lo_diff; int up = ffill_case == 0 ? 0 : up_diff; int flags = connectivity + (new_mask_val << 8) + (ffill_case == 1 ? CV_FLOODFILL_FIXED_RANGE : 0); int b = rand() & 255, g = rand() & 255, r = rand() & 255; CvConnectedComp comp;
if( is_mask ) cvThreshold( mask, mask, 1, 128, CV_THRESH_BINARY ); if( is_color ) { CvScalar color = CV_RGB( r, g, b ); cvFloodFill( color_img, seed, color, CV_RGB( lo, lo, lo ), CV_RGB( up, up, up ), &comp, flags, is_mask ? mask : NULL ); cvShowImage( "image", color_img ); } else { CvScalar brightness = cvRealScalar((r*2 + g*7 + b + 5)/10); cvFloodFill( gray_img, seed, brightness, cvRealScalar(lo), cvRealScalar(up), &comp, flags, is_mask ? mask : NULL ); cvShowImage( "image", gray_img ); }
printf("%g pixels were repainted\n", comp.area );
if( is_mask ) cvShowImage( "mask", mask ); } break; } }
int main( int argc, char** argv ) { char* filename = argc >= 2 ? argv[1] : (char*)"fruits.jpg";
if( (color_img0 = cvLoadImage(filename,1)) == 0 ) return 0;
printf( "Hot keys: \n" "\tESC - quit the program\n" "\tc - switch color/grayscale mode\n" "\tm - switch mask mode\n" "\tr - restore the original image\n" "\ts - use null-range floodfill\n" "\tf - use gradient floodfill with fixed(absolute) range\n" "\tg - use gradient floodfill with floating(relative) range\n" "\t4 - use 4-connectivity mode\n" "\t8 - use 8-connectivity mode\n" ); color_img = cvCloneImage( color_img0 ); gray_img0 = cvCreateImage( cvSize(color_img->width, color_img->height), 8, 1 ); cvCvtColor( color_img, gray_img0, CV_BGR2GRAY ); gray_img = cvCloneImage( gray_img0 ); mask = cvCreateImage( cvSize(color_img->width + 2, color_img->height + 2), 8, 1 );
cvNamedWindow( "image", 0 ); cvCreateTrackbar( "lo_diff", "image", &lo_diff, 255, NULL ); cvCreateTrackbar( "up_diff", "image", &up_diff, 255, NULL );
cvSetMouseCallback( "image", on_mouse, 0 );
for(;;) { int c; if( is_color ) cvShowImage( "image", color_img ); else cvShowImage( "image", gray_img );
c = cvWaitKey(0); switch( (char) c ) { case '\x1b': printf("Exiting ...\n"); goto exit_main; case 'c': if( is_color ) { printf("Grayscale mode is set\n"); cvCvtColor( color_img, gray_img, CV_BGR2GRAY ); is_color = 0; } else { printf("Color mode is set\n"); cvCopy( color_img0, color_img, NULL ); cvZero( mask ); is_color = 1; } break; case 'm': if( is_mask ) { cvDestroyWindow( "mask" ); is_mask = 0; } else { cvNamedWindow( "mask", 0 ); cvZero( mask ); cvShowImage( "mask", mask ); is_mask = 1; } break; case 'r': printf("Original image is restored\n"); cvCopy( color_img0, color_img, NULL ); cvCopy( gray_img0, gray_img, NULL ); cvZero( mask ); break; case 's': printf("Simple floodfill mode is set\n"); ffill_case = 0; break; case 'f': printf("Fixed Range floodfill mode is set\n"); ffill_case = 1; break; case 'g': printf("Gradient (floating range) floodfill mode is set\n"); ffill_case = 2; break; case '4': printf("4-connectivity mode is set\n"); connectivity = 4; break; case '8': printf("8-connectivity mode is set\n"); connectivity = 8; break; } }
exit_main:
cvDestroyWindow( "test" ); cvReleaseImage( &gray_img ); cvReleaseImage( &gray_img0 ); cvReleaseImage( &color_img ); cvReleaseImage( &color_img0 ); cvReleaseImage( &mask );
return 1; }
效果視訊我上傳了,瀏覽網址(個人感覺很牛,有點像生化危機裡的一個場景):
如果上面的卡,可以連這個,就是有點發散圖形:
也不說什麼了,直接給程式碼吧(有一句話想說,實際上如果你是拿來做實際專案的,可能並不要學習裡面的演算法,直接利用裡面的模板,也就是外接的呼叫函式就可以了):
#include "cv.h" #include "highgui.h" #include <time.h> #include <math.h> #include <ctype.h> #include <stdio.h> #include <string.h>
// various tracking parameters (in seconds) const double MHI_DURATION = 0.5; const double MAX_TIME_DELTA = 0.5; const double MIN_TIME_DELTA = 0.05; const int N = 3;
// const int CONTOUR_MAX_AERA = 16;
// ring image buffer IplImage **buf = 0; int last = 0;
// temporary images IplImage *mhi = 0; // MHI: motion history image
CvFilter filter = CV_GAUSSIAN_5x5; CvConnectedComp *cur_comp, min_comp; CvConnectedComp comp; CvMemStorage *storage; CvPoint pt[4];
// 引數: // img – 輸入視訊幀 // dst – 檢測結果 void update_mhi( IplImage* img, IplImage* dst, int diff_threshold ) { double timestamp = clock()/100.; // get current time in seconds CvSize size = cvSize(img->width,img->height); // get current frame size int i, j, idx1, idx2; IplImage* silh; uchar val; float temp; IplImage* pyr = cvCreateImage( cvSize((size.width & -2)/2, (size.height & -2)/2), 8, 1 ); CvMemStorage *stor; CvSeq *cont, *result, *squares; CvSeqReader reader;
if( !mhi || mhi->width != size.width || mhi->height != size.height ) { if( buf == 0 ) { buf = (IplImage**)malloc(N*sizeof(buf[0])); memset( buf, 0, N*sizeof(buf[0])); } for( i = 0; i < N; i++ ) { cvReleaseImage( &buf[i] ); buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 ); cvZero( buf[i] ); } cvReleaseImage( &mhi ); mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 ); cvZero( mhi ); // clear MHI at the beginning } // end of if(mhi)
cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
idx1 = last; idx2 = (last + 1) % N; // index of (last - (N-1))th frame last = idx2;
// 做幀差 silh = buf[idx2]; cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames // 對差影象做二值化 cvThreshold( silh, silh, 30, 255, CV_THRESH_BINARY ); // and threshold it cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI cvCvtScale( mhi, dst, 255./MHI_DURATION, (MHI_DURATION - timestamp)*255./MHI_DURATION ); cvCvtScale( mhi, dst, 255./MHI_DURATION, 0 ); // 中值濾波,消除小的噪聲 cvSmooth( dst, dst, CV_MEDIAN, 3, 0, 0, 0 ); // 向下取樣,去掉噪聲 cvPyrDown( dst, pyr, 7 ); cvDilate( pyr, pyr, 0, 1 ); // 做膨脹操作,消除目標的不連續空洞 cvPyrUp( pyr, dst, 7 ); // // 下面的程式段用來找到輪廓 // // Create dynamic structure and sequence. stor = cvCreateMemStorage(0); cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor); // 找到所有輪廓 cvFindContours( dst, stor, &cont, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); /* for(;cont;cont = cont->h_next) { // Number point must be more than or equal to 6 (for cvFitEllipse_32f). if( cont->total < 6 ) continue;
// Draw current contour. cvDrawContours(img,cont,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1, 8, cvPoint(0,0)); } // end of for-loop: "cont" */ // 直接使用CONTOUR中的矩形來畫輪廓 for(;cont;cont = cont->h_next) { CvRect r = ((CvContour*)cont)->rect; if(r.height * r.width > CONTOUR_MAX_AERA) // 面積小的方形拋棄掉 { cvRectangle( img, cvPoint(r.x,r.y), cvPoint(r.x + r.width, r.y + r.height), CV_RGB(255,0,0), 1, CV_AA,0); } } // free memory cvReleaseMemStorage(&stor); cvReleaseImage( &pyr ); }
int main(int argc, char** argv) { IplImage* motion = 0; CvCapture* capture = 0; //視訊獲取結構 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) //原型:extern int isdigit(char c); //用法:#include <ctype.h> 功能:判斷字元c是否為數字 說明:當c為數字0-9時,返回非零值,否則返回零。 capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( capture ) { cvNamedWindow( "Motion", 1 ); for(;;) { IplImage* image; if( !cvGrabFrame( capture )) //從攝像頭或者視訊檔案中抓取幀 break; image = cvRetrieveFrame( capture ); //取回由函式cvGrabFrame抓取的影象,返回由函式cvGrabFrame 抓取的影象的指標 if( image ) { if( !motion ) { motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 ); cvZero( motion ); motion->origin = image->origin; ///* 0 - 頂—左結構, 1 - 底—左結構 (Windows bitmaps 風格) */ } }
update_mhi( image, motion, 60 ); cvShowImage( "Motion", image );
if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Motion" ); } return 0; }
影象分割指的是將數字影象細分為多個影象子區域的過程,在OpenCv中實現了三種跟影象分割相關的演算法,它們分別是:分水嶺分割演算法、金字塔分割演算法以及均值漂移分割演算法。
分水嶺分割演算法 分水嶺分割演算法需要您或者先前演算法提供標記,該標記用於指定哪些大致區域是目標,哪些大致區域是背景等等;分水嶺分割演算法的分割效果嚴重依賴於提供的標記。OpenCv中的函式cvWatershed實現了該演算法
金字塔分割演算法 金字塔分割演算法由cvPrySegmentation所實現,該函式的使用很簡單;需要注意的是影象的尺寸以及金字塔的層數,影象的寬度和高度必須能被2整除,能夠被2整除的次數決定了金字塔的最大層數
均值漂移分割演算法 均值漂移分割演算法由cvPryMeanShiftFiltering所實現,均值漂移分割的金字塔層數只能介於[1,7]之間
友情連結一下,個人感覺比較好的這方面部落格:
效果圖:
#include "cv.h" #include "highgui.h" #include <math.h>
IplImage* image[2] = { 0, 0 }, *image0 = 0, *image1 = 0; CvSize size;
int w0, h0,i; int threshold1, threshold2; int l,level = 4; int sthreshold1, sthreshold2; int l_comp; int block_size = 1000; float parameter; double threshold; double rezult, min_rezult; CvFilter filter = CV_GAUSSIAN_5x5; CvConnectedComp *cur_comp, min_comp; CvSeq *comp; CvMemStorage *storage;
CvPoint pt1, pt2;
void ON_SEGMENT(int a) { cvPyrSegmentation(image0, image1, storage, &comp, level, threshold1+1, threshold2+1);
/*l_comp = comp->total;
i = 0; min_comp.value = cvScalarAll(0); while(i<l_comp) { cur_comp = (CvConnectedComp*)cvGetSeqElem ( comp, i ); if(fabs(255- min_comp.value.val[0])> fabs(255- cur_comp->value.val[0]) && fabs(min_comp.value.val[1])> fabs(cur_comp->value.val[1]) && fabs(min_comp.value.val[2])> fabs(cur_comp->value.val[2]) ) min_comp = *cur_comp; i++; }*/ cvShowImage("Segmentation", image1); }
int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)"fruits.jpg"; if( (image[0] = cvLoadImage( filename, 1)) == 0 ) return -1; cvNamedWindow("Source", 0); cvShowImage("Source", image[0]);
cvNamedWindow("Segmentation", 0);
storage = cvCreateMemStorage ( block_size );
image[0]->width &= -(1<<level); image[0]->height &= -(1<<level);
image0 = cvCloneImage( image[0] ); image1 = cvCloneImage( image[0] ); // 對彩色影象進行分割 l = 1; threshold1 =255; threshold2 =30;
ON_SEGMENT(1);
sthreshold1 = cvCreateTrackbar("Threshold1", "Segmentation", &threshold1, 255, ON_SEGMENT); sthreshold2 = cvCreateTrackbar("Threshold2", "Segmentation", &threshold2, 255, ON_SEGMENT);
cvShowImage("Segmentation", image1); cvWaitKey(0);
cvDestroyWindow("Segmentation"); cvDestroyWindow("Source");
cvReleaseMemStorage(&storage );
cvReleaseImage(&image[0]); cvReleaseImage(&image0); cvReleaseImage(&image1);
return 0; }
鬱悶,以前用過MatLab,很長時間沒用了,都不知道怎麼使了,據說做這個效果很不錯。
效果圖:
原始碼:
#include "cv.h" #include "highgui.h" /* src and dst are grayscale, 8-bit images; Default input value: [low, high] = [0,1]; X-Direction [bottom, top] = [0,1]; Y-Direction gamma ; if adjust successfully, return 0, otherwise, return non-zero. */ int ImageAdjust(IplImage* src, IplImage* dst, double low, double high, // X方向:low and high are the intensities of src double bottom, double top, // Y方向:mapped to bottom and top of dst double gamma ) { if( low<0 && low>1 && high <0 && high>1&& bottom<0 && bottom>1 && top<0 && top>1 && low>high) return -1; double low2 = low*255; double high2 = high*255; double bottom2 = bottom*255; double top2 = top*255; double err_in = high2 - low2; double err_out = top2 - bottom2;
int x,y; double val;
// intensity transform for( y = 0; y < src->height; y++) { for (x = 0; x < src->width; x++) { val = ((uchar*)(src->imageData + src->widthStep*y))[x]; val = pow((val - low2)/err_in, gamma) * err_out + bottom2; if(val>255) val=255; if(val<0) val=0; // Make sure src is in the range [low,high] ((uchar*)(dst->imageData + dst->widthStep*y))[x] = (uchar) val; } } return 0; }
int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0; if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1; cvNamedWindow( "src", 1 ); cvNamedWindow( "result", 1 ); // Image adjust dst = cvCloneImage(src); // 輸入引數 [0,0.5] 和 [0.5,1], gamma=1 if( ImageAdjust( src, dst, 0, 0.5, 0.5, 1, 1)!=0) return -1; cvShowImage( "src", src ); cvShowImage( "result", dst ); cvWaitKey(0);
cvDestroyWindow("src"); cvDestroyWindow("result"); cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; }
原始圖:
效果圖:
原始碼:
#inclu