日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

种子填充算法c语言代码实现,OpenGL绘图实例三之种子填充算法

發(fā)布時間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 种子填充算法c语言代码实现,OpenGL绘图实例三之种子填充算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

綜述

博主研究了一下午加一晚上,終于把種子填充算法實(shí)現(xiàn)出來并把機(jī)器人填充完畢,路途很艱辛,不過也學(xué)到了很多,在此和大家一起分享。

吐槽

與我不是同學(xué)的小伙伴,請自動忽略,我是來吐槽教材的。 在此不得不吐槽一下,不得不說教材實(shí)在太坑爹了。對于種子填充算法的后半部分,下一個種子點(diǎn)的尋找過程中,從while(x<=xright)開始,我實(shí)在無法搞懂它里面的神邏輯,最初我認(rèn)為它是對的,后來按照它的思路實(shí)現(xiàn)之后,填充基本上是錯誤的,比如圓角矩形下方的部分,它就無法正常填充。根本原因還是它的下一步種子點(diǎn)找錯了,而博主依然在固執(zhí)地DeBug,看看是不是我哪里編碼有問題。后來,干脆放棄了書上的邏輯了,自己改寫了搜尋下一個種子點(diǎn)的算法,最后終于成功。 另外,教材上的這些偽代碼寫得也是太偽,算了,這不是重點(diǎn),言歸正傳。

基本梳理

在博主的研究過程中,遇到了許許多多的小問題,在這里統(tǒng)一做一下總結(jié),也希望大家少走彎路,吸取我的經(jīng)驗(yàn)教訓(xùn)。

1.點(diǎn)的定義

在這里我們避免不了要使用點(diǎn),一個點(diǎn)包括了2個元素,一個是橫坐標(biāo)一個是縱坐標(biāo),所以我們可以直接把它定義為一個結(jié)構(gòu)體。

1

2

3

4

5

struct Point

{

int x;

int y;

};

這樣的話,我們就可以直接聲明一個 Point 類型的變量使用了,既方便又直觀。

2.棧的使用

對于種子填充算法,肯定避免不了使用棧的,在這里博主分享一下一些使用心得。 棧的引入 C++代碼中,可以直接用下面的代碼來導(dǎo)入

1

2

#include

using namespace std;

注意,這里一定記得加上 using namespace std 這句話,否則會出現(xiàn) stack 未定義的錯誤,哈哈哈,深有體會。 棧的定義 引入了棧之后,我們就可以直接來聲明一個棧了

1

stack pixelStack;

其中,需要加一個尖括號,尖括號中聲明了 Point 類型,這樣我們就可以使用它了 取棧頂元素 C++中取棧頂元素是很坑的,有一個top方法,還有一個pop方法。 其中top方法是只取得棧頂?shù)脑囟灰瞥?#xff0c;pop方法是直接移除棧頂元素,沒有返回值。 所以我們要想取出棧頂元素并移除的話,就要分別調(diào)用這兩個方法

1

2

3

4

//獲取最頂端的元素

Point tempPoint=pixelStack.top();

//刪除最頂端的元素

pixelStack.pop();

是不是不友好?不友好的話,那就自己去定義一個新方法吧,我就先不這么干啦。 判斷棧非空 判斷當(dāng)前的棧是否已經(jīng)為空,只需要調(diào)用empty方法就可以了

1

2

3

while(!pixelStack.empty()){

//code

}

這里是一個while循環(huán),如果棧為非空的話不斷循環(huán)。 關(guān)于棧置空 教材中的種子填充算法中用到了棧置空,不過我感覺沒有必要這么做,因?yàn)樵诜椒ㄗ钋懊媸切侣暶鞯臈W兞?#xff0c;它一定是空的。不過如果非要置空的話,可以利用下面的代碼

1

2

3

while(!pixelStack.empty()){

pixelStack.pop();

}

如果棧不為空,就一直取元素,就可以把它置空啦。

3.關(guān)于glColor3b和glColor3ub

這的確也是坑得博主不淺,之前一直在用 glColor3b 這個方法來定義顏色,奇怪的是 glColor3b(255,0,0) 竟然不是紅色,而是黑色!就是因?yàn)檫@個顏色問題,導(dǎo)致我在比對顏色的過程中走了很多彎路。在這里做一下說明 glColor3b()需要傳入的是byte類型,它的數(shù)值范圍是-128-127,也就是有符號數(shù),我傳入255,由于越界了,255這個數(shù)就相當(dāng)于-128,難怪不變紅啊。 glColor3ub()需要傳入的是unsigned byte類型,范圍是0-255,無符號數(shù),那么在這里我們傳入255,0,0這三個數(shù),就變成紅色了。

4.取得某像素顏色

我想說的是,這也是個深坑啊,一下午的Debug全歸它身上了。 獲取某個像素的這個函數(shù)是

1

void glReadPixels(GLint x,GLint y,GLsizesi width,GLsizei height,GLenum format,GLenum type,GLvoid *pixel);

函數(shù)說明如下:

該函數(shù)總共有七個參數(shù)。前四個參數(shù)可以得到一個矩形,該矩形所包括的像素都會被讀取出來。(第一、二個參數(shù)表示了矩形的左下角橫、縱坐標(biāo),坐標(biāo)以窗口最左下角為零,最右上角為最大值;第三、四個參數(shù)表示了矩形的寬度和高度) 第五個參數(shù)表示讀取的內(nèi)容,例如:GL_RGB就會依次讀取像素的紅、綠、藍(lán)三種數(shù)據(jù),GL_RGBA則會依次讀取像素的紅、綠、藍(lán)、alpha四種數(shù)據(jù),GL_RED則只讀取像素的紅色數(shù)據(jù)(類似的還有GL_GREEN,GL_BLUE,以及GL_ALPHA)。如果采用的不是RGBA顏色模式,而是采用顏色索引模式,則也可以使用GL_COLOR_INDEX來讀取像素的顏色索引。目前僅需要知道這些,但實(shí)際上還可以讀取其它內(nèi)容,例如深度緩沖區(qū)的深度數(shù)據(jù)等。 第六個參數(shù)表示讀取的內(nèi)容保存到內(nèi)存時所使用的格式,例如:GL_UNSIGNED_BYTE會把各種數(shù)據(jù)保存為GLubyte,GL_FLOAT會把各種數(shù)據(jù)保存為GLfloat等。 第七個參數(shù)表示一個指針,像素數(shù)據(jù)被讀取后,將被保存到這個指針?biāo)硎镜牡刂贰W⒁?#xff0c;需要保證該地址有足夠的可以使用的空間,以容納讀取的像素數(shù)據(jù)。例如一幅大小為256*256的圖象,如果讀取其RGB數(shù)據(jù),且每一數(shù)據(jù)被保存為GLubyte。

好了,那么重點(diǎn)來了,這個方法的坐標(biāo)基準(zhǔn)點(diǎn)是在畫布的左下角!!而我們繪圖的基準(zhǔn)點(diǎn)是在畫布的正中心!!所以我在獲取某個點(diǎn)的顏色的時候一直都是錯誤的結(jié)果,這樣的話在使用的時候我們的xy坐標(biāo)值就要加上畫布寬高的一半才能正常獲取到像素的顏色,希望大家一定注意!! 那么我們?nèi)绾蝸硎褂媚?#xff1f;實(shí)例如下,首先定義GLByte的數(shù)組

1

GLubyte iPixel[3];

另外還有畫布的寬度高度的一半變量

1

int halfWidth,halfHeight;

我們可以調(diào)用如下的方法來獲取(x,y)這個點(diǎn)像素的值

1

glReadPixels(x+halfWidth,y+halfHeight,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

在這里第五個參數(shù)我們定義了 GL_RGB,第六個參數(shù)我們定義了 GL_UNSIGNED_BYTE,最后是傳入了數(shù)組的引用。 所以在調(diào)用這個方法之后,iPixel數(shù)組里面的三個值就已經(jīng)賦值為了該點(diǎn)的RGB值,可以拿來做下一步的判斷。 比如我們邊界可以定義為

1

GLubyte oldColor[3]={255,255,255};

在比較的時候就可以用下面的判別式

1

iPixel[0]!=borderColor[0]&&iPixel[1]!=borderColor[1]&&iPixel[2]!=borderColor[2]

這里我們是依次比較了三個RGB值是否與邊界的RGB值相等,不過,有意思的是,識別顏色的這個方法,黑色的RGB值會識別成1,1,1,而有時候在我調(diào)試的時候會識別為0,1,1。我在想是不是系統(tǒng)計算誤差問題,如果真是的話,因?yàn)檫@個小小的誤差就影響了我們的判別條件豈不是虧大了?那么在這里我就定義了一個方法,允許一定的誤差,這個誤差姑且就稱為PS里面的容差吧。

1

2

3

4

5

6

7

8

9

10

//傳入兩個顏色的RGB值,比較是否相同,容差為dis

bool sameColor(int r1,int g1,int b1,int r2,int g2,int b2){

//容差度

int dis = 10;

if(abs(r1-r2)<=dis&&abs(g1-g2)<=dis&&abs(b1-b2)<=dis){

return true;

}else{

return false;

}

}

那么我們的判定條件就改為了

1

!sameColor(iPixel[0],iPixel[1],iPixel[2],borderColor[0],borderColor[1],borderColor[2])

這樣系統(tǒng)誤差便不會影響了。

5.下一個種子點(diǎn)的選取

教材上的種子點(diǎn)選取算法有點(diǎn)搞不懂,我按照上面的思路實(shí)現(xiàn)出來,在填充的時候出現(xiàn)了一系列問題。后來干脆放棄了教材中的方法,自己改寫了一下。 思路大體上是這樣的。

在填充完一行后,這一行最左邊的像素點(diǎn)我們定義為(xLeft,y),最右邊的像素我們定義為(xRight,y),掃描上一行找尋下一個種子點(diǎn),這里y就要增加1,如果(xRight,y+1)這個點(diǎn)不是邊界不是已經(jīng)填充的點(diǎn),那么這個點(diǎn)就可以作為種子點(diǎn)壓入堆棧。如果這個點(diǎn)是邊界或者是已經(jīng)填充的點(diǎn),那么就繼續(xù)往左搜索,如果找到既不是邊界又未填充的點(diǎn),那么這個點(diǎn)就是種子點(diǎn),壓入堆棧。如果一直往左找到xLeft還是沒有找到的話,就不存在下一個種子點(diǎn)了。下一行掃描線也是同樣的原理,y要在這個基礎(chǔ)上減去2即可。

恩,不知道大家有沒有看懂,這是我自己想出來的方法,不敢保證完全正確,在此僅供參考。 如果大家真的可以按照教材中的方法實(shí)現(xiàn)成功的話,希望告訴我一下,感激不盡。

方法實(shí)現(xiàn)

恩,重要的地方都已經(jīng)點(diǎn)明了,下面就直接附上我的種子填充算法吧!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

//種子填充算法

void zzFill(int startX,int startY,int r,int g,int b){

stack pixelStack;

//x,y是給定的種子像素點(diǎn),rgb就是要填充的顏色的RGB值

Point point = {startX,startY};

pixelStack.push(point);

int saveX;

int xRight,xLeft;

int x,y;

//如果棧不為空

while(!pixelStack.empty()){

//獲取最頂端的元素

Point tempPoint=pixelStack.top();

//刪除最頂端的元素

pixelStack.pop();

saveX=tempPoint.x;

x=tempPoint.x;

y=tempPoint.y;

glReadPixels(x+halfWidth,y+halfHeight,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

//如果沒有到達(dá)右邊界,就填充

while(!sameColor(iPixel[0],iPixel[1],iPixel[2],borderColor[0],borderColor[1],borderColor[2])){

glPoint(x,y,r,g,b);

x=x+1;

glReadPixels(x+halfWidth,y+halfHeight,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

}

xRight=x-1;

x=saveX-1;

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

//如果沒有到達(dá)左邊界,就填充

while(!sameColor(iPixel[0],iPixel[1],iPixel[2],borderColor[0],borderColor[1],borderColor[2])){

glPoint(x,y,r,g,b);

x=x-1;

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

}

//保存左端點(diǎn)

xLeft=x+1;

//從右邊的點(diǎn)開始

x=xRight;

//檢查上端的掃描線

y=y+1;

while(x>=xLeft){

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

if(!sameColor(iPixel[0],iPixel[1],iPixel[2],borderColor[0],borderColor[1],borderColor[2])&&!sameColor(iPixel[0],iPixel[1],iPixel[2],r,g,b)){

//如果上方的點(diǎn)不是邊界點(diǎn),直接壓入

Point p={x,y};

pixelStack.push(p);

//壓入之后停止循環(huán)

break;

}else{

x--;

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

}

}

//檢查下端的掃描線

y=y-2;

//從右邊的點(diǎn)開始

x=xRight;

while(x>=xLeft){

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

if(!sameColor(iPixel[0],iPixel[1],iPixel[2],borderColor[0],borderColor[1],borderColor[2])&&!sameColor(iPixel[0],iPixel[1],iPixel[2],r,g,b)){

//如果上方的點(diǎn)不是邊界點(diǎn),直接壓入

Point p={x,y};

//壓入之后停止循環(huán)

pixelStack.push(p);

break;

}else{

x--;

glReadPixels(x+halfWidth,y+halfWidth,1,1,GL_RGB,GL_UNSIGNED_BYTE,&iPixel);

}

}

}

}

以上便是我實(shí)現(xiàn)的種子填充算法,僅供參考 在這里我們用到了glPoint畫點(diǎn)的方法,這是我們定義的,方法如下,為了便于調(diào)試,每畫一個點(diǎn)刷新一下,這樣我們就可以看到繪制的全部動態(tài)效果。

1

2

3

4

5

6

7

8

9

//畫點(diǎn)

void glPoint(int x,int y,int r,int g,int b){

glColor3ub (r,g,b);

glPointSize(1);

glBegin(GL_POINTS);

glVertex2i(x,y);

glEnd();

glFlush();

}

以上便是畫點(diǎn)的函數(shù)

方法使用

種子填充算法肯定要在我們繪制完機(jī)器人之后使用,任意選取某個四連通區(qū)域的點(diǎn),傳入xy坐標(biāo)值還有要填充的顏色的RGB值,就可以成功實(shí)現(xiàn)填充。 在上一篇機(jī)器人的基礎(chǔ)上,我們在畫機(jī)器人的方法最后加入下面的代碼,即可實(shí)現(xiàn)填充。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

//灰色:195,195,195

//黃色:255,243,0

//紅色:237,28,36

//深灰色:126,126,126

//脖子

zzFill(0,70,195,195,195);

//頭

zzFill(-50,110,195,195,195);

zzFill(0,93,195,195,195);

//肚子

zzFill(-50,0,195,195,195);

//耳朵

zzFill(-80,115,126,126,126);

zzFill(80,115,126,126,126);

//肚子三角

zzFill(-20,-10,255,243,0);

//肚子紅色圓

zzFill(0,0,237,28,36);

//zzFill(-50,0,128,255,33);

//大臂

zzFill(-90,30,126,126,126);

zzFill(90,30,126,126,126);

//小臂

zzFill(-90,-20,126,126,126);

zzFill(90,-20,126,126,126);

//手

zzFill(-75,40,195,195,195);

zzFill(75,40,195,195,195);

//手

zzFill(-95,-47,195,195,195);

zzFill(95,-47,195,195,195);

//大腿連接處

zzFill(-40,-64,195,195,195);

zzFill(40,-64,195,195,195);

//大腿

zzFill(-40,-100,126,126,126);

zzFill(40,-100,126,126,126);

//腳踝

zzFill(-40,-121,195,195,195);

zzFill(40,-121,195,195,195);

//腳掌

zzFill(-40,-130,126,126,126);

zzFill(40,-130,126,126,126);

system("pause");

注意,有個很奇怪地方是繪制完了之后機(jī)器人就不見了,所以在這里加入了system(“pause”)方法來暫停一下就好啦。 其他的代碼基本都是上一篇中的了,大家自行整理。

運(yùn)行結(jié)果

運(yùn)行結(jié)果截圖如下 恩,就是這樣!

總結(jié)

以上便是博主利用種子填充算法來實(shí)現(xiàn)的機(jī)器人的顏色填充,在此分享給大家,希望對大家有幫助! 如有問題和錯誤,歡迎大家給予我批評和指正,謝謝!

總結(jié)

以上是生活随笔為你收集整理的种子填充算法c语言代码实现,OpenGL绘图实例三之种子填充算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久福利 | 老司机成人免费视频 | 97超碰中文字幕 | 日韩视频不卡 | 日本高清xxx | 无码播放一区二区三区 | 日韩一区二区三区精品视频 | 色视频免费观看 | 一级黄色短片 | 激情婷婷久久 | 欧美日韩中 | 久久精品10| 少妇又紧又色又爽又刺激视频 | 国产精品入口夜色视频大尺度 | 国产成人在线观看网站 | 中文在线a√在线8 | 极品粉嫩小仙女高潮喷水久久 | 亚洲男人天堂网 | 国产91丝袜在线播放九色 | 国产刺激高潮av | 国产女主播自拍 | 天天鲁 | 用力使劲高潮了888av | 亚洲青青草 | 日日麻批免费视频播放 | 成人精品亚洲 | 91字幕网| 手机看片亚洲 | 国产精品无码一区二区无人区多人 | 特a级黄色片| 亚洲男人天堂网 | 香蕉av网站 | 欧美熟女一区二区 | 国产sm在线 | 校园激情亚洲 | ts人妖在线| 97人人爱 | 国产不雅视频 | wwwxxx黄色| av在线一区二区 | 天天干天天天 | 人妻无码中文字幕免费视频蜜桃 | 国产福利免费视频 | 麻豆md0077饥渴少妇 | 欧美日韩人妻精品一区二区 | 制服诱惑一区二区三区 | 欧美不卡在线视频 | 日韩av在线电影 | 日日夜夜国产 | 波多野结衣导航 | 裸体美女免费视频网站 | 国产乡下妇女三片 | 亚洲成人av综合 | 亚洲在线综合 | 懂色tv | 天美乌鸦星空mv | 欧洲午夜精品 | 国产精品免费一区二区三区都可以 | 亚洲自拍偷拍在线 | 欧美黄色片免费看 | 欧美精品xxxxx | 色婷婷中文字幕 | 综合网伊人 | 强迫凌虐淫辱の牝奴在线观看 | 天堂在线资源网 | 人人爽人人爽人人爽人人爽 | 狠狠干夜夜草 | 欧洲av网站 | 亚洲人天堂 | 青青草超碰 | 性日本xxx | 国产免费一区二区三区四区五区 | 男女激情啪啪 | 国产人妖在线播放 | 爆乳2把你榨干哦ova在线观看 | 久艹视频在线观看 | 猫咪av网| 久久不射电影网 | 男人天堂视频在线观看 | av大片在线看 | 久久久久高潮 | 日韩女同互慰一区二区 | 黄色正能量网站 | 日日摸夜夜添狠狠添欧美 | 狠狠人妻久久久久久 | 日日噜噜夜夜狠狠久久丁香五月 | 亚洲成人第一网站 | 亚洲AV无码精品久久一区二区 | 久久精品99北条麻妃 | 亚洲视频 一区 | 亚洲精品乱码久久久久 | av中文字幕网 | 射进来av影视 | 成人亚洲精品 | 99精品国产成人一区二区 | 91爱爱网站 | 欧美一区二区三区精品 | 亚洲av永久无码精品一百度影院 | 超碰caoprom|