2008年6月23日 星期一

隨機,字型與繪圖

在這邊拿OpenCV的Sample code,"drawing.c"來做例子,這個程式碼播放的是很漂亮的動畫,而且大部分的字型函式及繪圖函式都被用到了,下面的程式碼已經被修改的跟"drawing.c"不太一樣了,其實執行結果除了給他隨機的Seed不同之外其他是相同的,增加了程式的易讀性,但是下面還是有用到一些技巧及資料結構需要去被理解的.

Drawing.c程式碼修改
#include <cv.h>
#include <highgui.h>


IplImage *Image1,*Image2;

CvScalar RandomColor(CvRNG* rng);
void DrawingLine(CvRNG *rng);
void DrawingRectangle(CvRNG *rng);
void DrawingEllipse(CvRNG *rng);
void DrawingPolyLine(CvRNG *rng);
void DrawingFillPoly(CvRNG *rng);
void DrawingCircle(CvRNG *rng);
void WritingText(CvRNG *rng);
void OpenCVForever(CvRNG *rng);

int main()
{
    CvRNG rng;
    rng = cvRNG(cvGetTickCount());

    CvSize ImageSize1 = cvSize(1000,700);
    Image1 = cvCreateImage(ImageSize1,8,3);
    cvZero(Image1);

    cvNamedWindow("Drawing",1);
    cvShowImage("Drawing",Image1);

    DrawingLine(&rng);
    DrawingRectangle(&rng);
    DrawingEllipse(&rng);
    DrawingPolyLine(&rng);
    DrawingFillPoly(&rng);
    DrawingCircle(&rng);
    WritingText(&rng);
    OpenCVForever(&rng);

    cvWaitKey(0);

}
CvScalar RandomColor(CvRNG* rng)
{
    int icolor = cvRandInt(rng);
    return CV_RGB(icolor&255,(icolor>>8)&255,(icolor>>16)&255);
}
void DrawingLine(CvRNG *rng)
{
    CvPoint FromPoint,ToPoint;
    CvScalar Color;
    int Thickness;
    for(int i=0;i<100;i++)
    {
        FromPoint = cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        ToPoint = cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);

        Color=RandomColor(rng);
        Thickness=cvRandInt(rng)%10;

        cvLine(Image1,FromPoint,ToPoint,Color,Thickness,CV_AA,1);

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}

void DrawingRectangle(CvRNG *rng)
{
    CvPoint VertexOne,VertexThree;
    CvScalar Color;
    int Thickness;
    for(int i=0;i<100;i++)
    {
        VertexOne=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        VertexThree=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);

        Color=RandomColor(rng);
        Thickness=cvRandInt(rng)%10-1;

        cvRectangle(Image1,VertexOne,VertexThree,Color,Thickness,CV_AA,0);
        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}
void DrawingEllipse(CvRNG *rng)
{
    CvPoint CircleCenter;
    CvSize EllipseSize;
    double angle;
    double DrawStart;
    double DrawStop;
    CvScalar Color;
    int Thickness;
    for(int i =0;i<100;i++)
    {
        CircleCenter=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        EllipseSize=cvSize(cvRandInt(rng)%200,cvRandInt(rng)%200);

        angle = (cvRandInt(rng)%1000)*0.180;
        DrawStart=angle-100;
        DrawStop=angle+200;
        Color=RandomColor(rng);
        Thickness=cvRandInt(rng)%10-1;

        cvEllipse(Image1,CircleCenter,EllipseSize,angle,DrawStart,DrawStop,Color,Thickness,CV_AA,0);

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}

void DrawingPolyLine(CvRNG *rng)
{
    CvPoint PointArray1[6];
    CvPoint *PointArray[2]={&PointArray1[0],&PointArray1[3]};

    int PointNumber[2]={3,3};
    int BlockNumber=2;
    int IsClosed=1;
    CvScalar Color;
    int Thickness;
    for(int i=0;i<100;i++)
    {
        PointArray[0][0]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[0][1]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[0][2]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][0]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][1]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][2]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);

        Color=RandomColor(rng);
        Thickness=cvRandInt(rng)%10;

        cvPolyLine(Image1,PointArray,PointNumber,BlockNumber,IsClosed,Color,Thickness,CV_AA,0);

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}

void DrawingFillPoly(CvRNG *rng)
{
    CvPoint PointArray1[6];
    CvPoint *PointArray[2]={&PointArray1[0],&PointArray1[3]};

    int PointNumber[2]={3,3};
    int BlockNumber=2;

    CvScalar Color;

    for(int i=0;i<100;i++)
    {
        PointArray[0][0]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[0][1]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[0][2]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][0]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][1]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        PointArray[1][2]=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        Color=RandomColor(rng);

        cvFillPoly(Image1,PointArray,PointNumber,BlockNumber,Color,CV_AA,0);

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}
void DrawingCircle(CvRNG *rng)
{
    CvPoint CircleCenter;
    int Radius;
    CvScalar Color;
    int Thickness;
    for(int i=0;i<100;i++)
    {
        CircleCenter=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);

        Radius=cvRandInt(rng)%300;
        Color=RandomColor(rng);
        Thickness=cvRandInt(rng)%10-1;

        cvCircle(Image1,CircleCenter,Radius,Color,Thickness,CV_AA,0);
        cvShowImage("Drawing",Image1);

        cvWaitKey(5);
    }
}
void WritingText(CvRNG *rng)
{
    CvFont Font1;
    int FontFace;
    double HorizontalScale;
    double VerticalScale;
    double Shear;
    int Thickness;

    CvPoint TextPosition;     CvScalar Color;
    for(int i=1;i<100;i++)
    {
        TextPosition=cvPoint(cvRandInt(rng)%3000-1000,cvRandInt(rng)%2100-700);
        FontFace=cvRandInt(rng)%8;
        HorizontalScale=(cvRandInt(rng)%100)*0.05+0.1;
        VerticalScale=(cvRandInt(rng)%100)*0.05+0.1;
        Shear=(cvRandInt(rng)%5)*0.1;
        Thickness=cvRound(cvRandInt(rng)%10);
        Color=RandomColor(rng);

        cvInitFont(&Font1,FontFace,HorizontalScale,VerticalScale,Shear,Thickness,CV_AA);
        cvPutText(Image1,"GO GO GO!",TextPosition,&Font1,Color);

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}
void OpenCVForever(CvRNG *rng)
{
    CvFont Font1;
    CvSize TextSize;
    int Baseline = 0;
    CvPoint TextPosition;

    cvInitFont(&Font1,CV_FONT_HERSHEY_COMPLEX,3,3,0.0,5,CV_AA);
    cvGetTextSize("OpenCV forever!",&Font1,&TextSize,&Baseline );

    TextPosition =cvPoint((1000 - TextSize.width)/2,(700 + TextSize.height)/2);
    Image2 = cvCloneImage(Image1);

    for(int i = 0; i < 255; i++ )
    {
        cvSubS(Image2,cvScalarAll(i),Image1,0);

        cvPutText(Image1,"OpenCV forever!", TextPosition,&Font1,CV_RGB(255,i,i));

        cvShowImage("Drawing",Image1);
        cvWaitKey(5);
    }
}

執行結果:


這個解釋可多的呢,先宣告一個CvRNG的資料結構,為OpenCV的隨機資料結構,再用cvRNG()初始化,初始化的副程式內,給定了一個cvGetTickCount()OpenCV內建時間副程式來當做隨機副程式的種子,如果有用過C語言的srand()及rand()功能的話大致上應該能了解,如果不給定一個種子(Seed),則它隨機出來的數字是固定的,而它給定隨機種子的範圍,是正整數64bits的大小,也就是0~2^64數字大小,接著在開啟了一個1000*700大小的圖片顯示視窗,而它隨機的範圍是從3000*2100,讓隨機出來的圖型可以有那種不完整的感覺,接下來用分類的方式表達:

1.RandomColor()
回傳一個隨機的像素值,也就是R+G+B,這邊的隨機方式很有趣,因為他用到了一些小技巧,一張圖是由光的三原色紅綠藍所組合而成的,而紅綠藍三原色的範圍是0~255,它這邊所使用的技巧是AND運算以及位移運算,由cvRandInt()所回傳的數是32bits的整數,而實際上,三原色0~255所用到的位元數是8bits,所以,就直接對該數字做AND運算,可以得到他最後面8bits的數字,再對它做位移運算,往後移動8bits,再用AND運算擷取接下來的8bits,因此,32bits的隨機有16bits被RGB三原色用到啦,這個困難點在於,並不是所有的數字都是絕對的,它只適用2^n-1的數字時使用,也就是1,3,7,15,31,63,127,255...這個就要說到AND運算的原理啦,用起來沒有比cvRandInt()%256方便就是了,不過運算速度會比cvRandInt()%256還快.

2.DrawingLine()
這裡隨機產生了100條線段,繪製一條線的需求為給定一張IplImage格式的圖,線段起點座標,線段終點座標,線段顏色,線段的粗細程度,線段的類型(CV_AA),輸入的座標,粗細到小數點第幾位,這裡坐標,顏色,粗細給定一個隨機值來產生100條線段.

3.DrawingRectangle()
隨機產生100個方框,方框需要的是給定一個IplImage格式的圖,對角線的座標位置(頂點1跟頂點3),方框顏色,方框粗細,方框線條類型等,而這邊隨機了頂點,顏色,粗細.

4.DrawingEllipse()
隨機產生100個橢圓,橢圓需要IplImage的圖,圓心,橢圓的大小,旋轉角度,及他的繪圖起點到繪圖終點,如果說繪圖起點不是0,繪圖終點不是360,則它繪出來的圖會是一個弧形線段,有缺口的橢圓,再來是橢圓顏色,橢圓線條種類等,這邊角度,顏色,粗細都是隨機的.

5.DrawingPolyLine()
隨機產生100個多邊型,這邊多邊形的函式運用到一些小技巧,除了給定了IplImage資料結構之外,還要給定它點(CvPoint)陣列,也就是所有點的集合,把它存在一個以CvPoint宣告的一維陣列裡,但是這邊cvPolyLine()為什麼要給它的是二維陣列呢,因為這個函式,可以畫兩個以上的多邊型,而它可以存在好幾百個點,或好幾千的點(頂點),而這樣,就會降低了它的存取效能,這邊程式給它了最佳化的的方法,也就是設立Index,跟資料庫原理相同的,這邊設計是每3個陣列空間就做Index,加快點的一維陣列存取速度,其實說穿了也只是用二維陣列表示罷了但實際上,它的Index在多邊型cvPolyLine()是不具任何意義的,可以自由的設定Index的寬度.cvPolyLine()除了點陣列以外,還有多邊型點集合數目這邊的設定是{3,3}表示每三個點變成一個多邊形集合,也就是兩個三角形,如果把它改成PointNumber[1]={6}的話就是標準的六邊型了.再來cvPolyLine()下一個引數是區塊數(也就是多邊行內部對角線要被對角線劃分多少區塊),再一個引數為是否要被圍繞成一個多邊型(圖論的問題,路徑(path)跟路線(trail)),多邊型顏色,線條種類等,這邊點集合,顏色,粗細都是隨機的.

6.DrawingFillPoly()
隨機產生100個被填滿的多邊型,也就是實心的,非線段的,用IplImage資料結構,點集合陣列,組成多邊點集合數目,區塊數,填滿區域的顏色,邊線種類,輸入的點陣列,邊線等數據到小數點第幾位,而點集合,填滿區域的顏色為隨機產生的.

7.DrawingCircle()
隨機產生100個圓形,需要用到IplImage資料結構,圓心座標,半徑長度,圓形線段顏色,圓形粗細,線條種類,輸入座標,半徑長度,粗細數據到小數點第幾位,這邊圓心座標,半徑,圓形顏色,粗細都是隨機的.

8.WritingText()
產生100個文字訊息,要用到Font字型資料結構,先初始化Font資料結構,而cvInitFont()包含字型的種類,水平跟鉛直大小,文字的頃斜程度(Shear),文字的粗細寬度,線條種類,輸入水平,鉛直,頃斜,粗細的數據到小數點第幾位,這邊字型種類,水平鉛直,文字頃斜度,線條粗細都是隨機的. 在放置文字訊息,cvPutText()包含目標圖片,文字訊息,字型資料結構以及文字的顏色,而這邊顏色跟位置是隨機的.

9.OpenCVForever()
同8.這邊不同的是,用cvSubS()來做到灰階漸暗的效果,並且將文字訊息顯示在中間

3 意見:

匿名 提到...

為什麼你貼的程式碼會有顏色
為什麼?為什麼?!為什麼????
from 偉崇

wa114040@gmail.com 提到...

像我這種時間太多的才可以去做慢慢上色的動作(Kill time)XD

匿名 提到...

XD

Copyright 2008-2009,yester