2008年7月17日 星期四

資料結構操作與運算-IplImage,CvMat的算數運算

算數運算,最基本的就是加減乘除啦,OpenCV提供了圖形及矩陣加減乘除的函式,而這邊的乘法除法不是一般矩陣運算的乘除,而是兩個矩陣數據互相做相乘,並不是我們一般所學的矩陣乘法,除的部份也是一樣,矩陣乘法會在後面提到.

圖形空間的算數運算
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    CvCapture *capture;
    IplImage *frame,*frame1,*frame2;

    frame1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
    frame2=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);

    capture =cvCaptureFromCAM(0);

    cvNamedWindow("Webcam",0);

    while(true)
    {
        frame = cvQueryFrame(capture);
        cvSub(frame,frame1,frame2);
        cvAdd(frame2,frame,frame2);
        cvFlip(frame2,frame2,0);   // frame2->origin=1;

        cvShowImage("Webcam",frame2);

        if(cvWaitKey(10)>=0)    break;

        printf("%d",frame->origin);
        printf("%d",frame2->origin);

        cvCopy(frame,frame1);

    }

    cvReleaseCapture(&capture);
    cvReleaseImage(&frame1);
    cvReleaseImage(&frame2);
    cvDestroyWindow("Webcam");
}

上面的程式可好玩多了,執行後會製造出殘像的效果,由於前一張frame減後一張frame,所製造出來的差異再跟原始影像做相加,因此影像會因為運動後而產生差異,對於影像的相減及相加,由於uchar格式的圖片範圍界在0~255之間,因此全部的最小值會為0,最大值會為255,不會有負號的存在,它會自動變為0,因此,對於連續影像的運算不適合uchar的型別,可以用前面型別轉換的方式,或是把它轉成RGB三個float型別的二維陣列自己做連續影像的計算.而這邊cvQueryFrame()所擷取的視訊圖片為上下顛倒的圖形影像,跟cvCreateImage()創造出來的圖像是相反的,解決的方法是把origin設為1,或是用cvFlip()來做圖形的翻轉.origin的部份可以參考前面IplImage資料結構介紹的部份.

矩陣空間的算數運算
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


float MatrixData1[]={1,2,3,4,5,6,7,8,9};
float MatrixData2[]={8,7,6,5,4,3,2,1,0};
float MatrixData3[9];
void PrintMatrix(CvMat *Matrix);

int main()
{
    CvMat Matrix1=cvMat(3,3,CV_32FC1,MatrixData1);
    CvMat Matrix2=cvMat(3,3,CV_32FC1,MatrixData2);
    CvMat Matrix3=cvMat(3,3,CV_32FC1,MatrixData3);

    printf("\nMatrix Add:\n");
    cvAdd(&Matrix1,&Matrix2,&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix Sub:\n");
    cvSub(&Matrix1,&Matrix2,&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix Mul:\n");
    cvMul(&Matrix1,&Matrix2,&Matrix3,2);
    PrintMatrix(&Matrix3);

    printf("\nMatrix Div:\n");
    cvDiv(&Matrix1,&Matrix2,&Matrix3,3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix AddS:\n");
    cvAddS(&Matrix1,cvRealScalar(4),&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix SubS:\n");
    cvSubS(&Matrix1,cvRealScalar(5),&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix SubRS:\n");
    cvSubRS(&Matrix1,cvRealScalar(2),&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix SubRS:\n");
    cvScaleAdd(&Matrix1,cvRealScalar(3),&Matrix2,&Matrix3);
    PrintMatrix(&Matrix3);

    printf("\nMatrix AddWeighted:\n");
    cvAddWeighted(&Matrix1,2,&Matrix2,-4,5,&Matrix3);
    PrintMatrix(&Matrix3);

    system("pause");
}

void PrintMatrix(CvMat *Matrix)
{
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            printf("%.1f ",cvGet2D(Matrix,i,j).val[0]);
        }
        printf("\n");
    }
}

執行結果:


上面的程式是矩陣所有加減乘除的函式,而乘跟除不是標準矩陣運算,矩陣運算的部份就要參考後面線性代數的地方,上面cvAdd(),cvAddS(),cvSub(),cvSubS()cvSubRS()都具有Mask遮罩的功能,遮罩的部份也是會在後面詳細敘述,以下為各算數運算的計算方式

1.cvAdd(&Matrix1,&Matrix2,&Matrix3)


2.cvSub(&Matrix1,&Matrix2,&Matrix3)


3.cvMul(&Matrix1,&Matrix2,&Matrix3,2)


4.cvDiv(&Matrix1,&Matrix2,&Matrix3,3)


5.cvAddS(&Matrix1,cvRealScalar(4),&Matrix3)


6.cvSubS(&Matrix1,cvRealScalar(5),&Matrix3)


7.cvSubRS(&Matrix1,cvRealScalar(2),&Matrix3)


8.cvScaleAdd(&Matrix1,cvRealScalar(3),&Matrix2,&Matrix3)


9.cvAddWeighted(&Matrix1,2,&Matrix2,-4,5,&Matrix3)


5~7的S代表的就是全1矩陣的純量積(Scalar multiplication).

cvAdd()
矩陣加法運算,適用於IplImage及CvMat資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別,具有遮罩的功能.
cvAdd(輸入IplImage或CvMat結構,輸入IplImage或CvMat結構,輸出IplImage或CvMat結構,IplImage資料結構目標Mask區域)

cvSub()
矩陣減法運算,適用於IplImage及CvMat資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別,且具有遮罩的功能.
cvAdd(輸入IplImage或CvMat結構,輸入IplImage或CvMat結構,輸出IplImage或CvMat結構,IplImage資料結構目標Mask區域)

cvMul()
矩陣內部乘法運算,非一般矩陣乘法,具有兩個IplImage或CvMat資料結構矩陣輸入,一個純量輸入及一個矩陣輸出,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvMul(輸入IplImage或CvMat結構,輸入IplImage或CvMat結構,輸出IplImage或CvMat結構,純量數據)

cvDiv()
矩陣內部除法運算,非一般矩陣運算,具有兩個IplImage或CvMat資料結構矩陣輸入,一個純量輸入及一個矩陣輸出,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvADiv(輸入IplImage或CvMat結構,輸入IplImage或CvMat結構,輸出IplImage或CvMat結構,純量數據)

cvAddS()
目標矩陣與全1矩陣的純量積加法,也就是矩陣內全部數據加某數,第一個引數為IplImage資料結構或CvMat資料結構,第二個為CvScalar資料結構,因此可支援多通道,第三個為輸出資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvAddS(輸入IplImage或CvMat結構,CvScalar資料結構,輸出IplImage或CvMat結構)

cvSubS()
目標矩陣與全1矩陣的純量積減法,也就是矩陣內全部數據減去某數,第一個引數為IplImage資料結構或CvMat資料結構,第二個為CvScalar資料結構,第三個為輸出資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvSubS(輸入IplImage或CvMat結構,CvScalar資料結構,輸出IplImage或CvMat結構)

cvSubRS()
全1矩陣的純量積減目標矩陣,也就是矩陣內全部數據加負號加上某數,第一個引數為IplImage資料結構或CvMat資料結構,第二個為CvScalar資料結構,因此可支援多通道,第三個為輸出資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvSubRS(輸入IplImage或CvMat結構,CvScalar資料結構,輸出IplImage或CvMat結構)

cvScaleAdd()
第一個輸入矩陣的純量積加上第二個輸入矩陣,第一個引數為IplImage資料結構或CvMat資料結構,第二個為CvScalar資料結構,因此可支援多通道,第三個為欲加上的矩陣資料結構,第四個為輸出資料結構,輸入跟輸出資料結構必須同類型,同大小,同型別.
cvSubRS(輸入IplImage或CvMat結構,CvScalar資料結構,輸入IplImage或CvMat結構,輸出IplImage或CvMat結構)

cvAddWeighted()
主要的方式是以權重去分配每個矩陣的比值,分別為第一個矩陣純量積加上第二個矩陣純量積加上全1矩陣純量積,這邊只能做單通道的運算.
cvSubRS(輸入IplImage或CvMat結構,double型別純量數據,輸入IplImage或CvMat結構double型別純量數據,double型別純量數據,輸出IplImage或CvMat結構)



4 意見:

匿名 提到...

文中的函数cvAdd()应该改为cvAdd(frame2,frame,frame);才能实现。作者笔误了吧 :-)

俊哲 提到...
作者已經移除這則留言。
匿名 提到...

為何會有cvCopy' : too few actual parameters

匿名 提到...

一樓講錯囉
我們要輸出的是frame2

Copyright 2008-2009,yester