السلام عليكم
الهدف من المقال :
خوارزمية Fill Flood :

صورة من الويكي.
السلام عليكم
الهدف من المقال :
خوارزمية Fill Flood :

صورة من الويكي.
تم تعديل هذه المشاركة بواسطة الشمري في 10 ديسمبر 2009 في 06:58
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri
وعليكم السلام و رحمة الله
بشوق للقادم
رعاك الله و جعل جنان الخلد مثواك
بالانتظار رعاك الله
شرح رائع والخوارزميه بسيطه ومفيده :)
ياريت بما إنك في موضوع الرسوميات تكمل شرح أدوات في الفوتوشوف مثل البلور كيف يتم وماهي الخوارزميه الخاصه به وعمل negative وغيرها من الأمور
إذا كانت هاي الأمور موجوده في القسم فماتواخذوني :) دوبي لقيت هيك مواضيع فتحمست
جزاك الله خير
حياكم الله يا أخوان ، ( تم رفع المثال البسيط الخاص بالخوارزمية السابقة Flood Fill - في المشاركة الاولى )
اقتباسياريت بما إنك في موضوع الرسوميات تكمل شرح أدوات في الفوتوشوف مثل البلور كيف يتم وماهي الخوارزميه الخاصه به وعمل negative وغيرها من الأمور
الموضوع طويل قليلاً ( وليس لي باع طويل ، ) لكن النية موجودة للحديث عن بعض الخوارزميات ان شاء الله .
الخوارزمية الثانية : Boundary Fill
تم تعديل هذه المشاركة بواسطة الشمري في 3 ديسمبر 2009 في 10:48
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri
رائع بارك الله فيك
قرأت أن الأفضل من تلك الخوارزميتين
هي تعبئة البكسلات التي تقع على scan line
اذا ممكن توضيح الفكرة
ولي عودة بإذن الله
نعم ، لكن لاأعرف هل scan line هي أفضل الخوارزميات ، لكن هي أفضل من الخوارزميتين السابقتين عموماً ،
درست هذه الخوارزمية تحت اسم اخر ، باسم runs of pixels ، أعتقد هي نفسها scan line ،
لم أعمل تجربة " كود " لهذه الخوارزمية ، من قبل ، فقط دراسة نظرية ، حيث أنها ليست بالمعقدة " نظرياً على الاقل " ،
ممكن أكتب عنها ، ان لم يتبرع أحد ويقوم بالمهمة :-) .
تم تعديل هذه المشاركة بواسطة الشمري في 3 ديسمبر 2009 في 20:15
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri
السلام عليكم و رحمة الله و بركاته
حاولت فهم الكود و التجربه اكثر من مره و لكن يوجد بعض الاشياء اتمنى توضيحها حيث اني مبتدئة في الرسم بالحاسب
اتمنى التوضيح لي عاجلا رعاك الله
أرفقت البرنامج و و بداخله كتبت استفساراتي boundary-fill.rar
هل SEED ALGORITHM يطلق فقط على FLOOD FILL
قرأت انها تطلق فقط على FLOOD
و البعض يعتبر ان BOUNDARY و FLOOD يطلق عليهم SEED ALGORITHM
-----------
وكان لدي ملاحظة هنا
كنت أنت تبدأ اللوب من قيم Y و لكني وجدتها تطبع قيمة مختلفة لمكان المربع الاسود الداخلي
فعدلته بالبدء من X
void display()
{
//glClearColor(0.8,0.8,0.8,1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
//glTranslatef(0,0,0);
drawImage();
// debug
for(int x=0;x<CELL_NUMBER;x++)
{
for(int y=0;y<CELL_NUMBER;y++)
{
cout << image[x][y] <<" ";
}
cout << endl;
}
cout << endl;
glutSwapBuffers();
}
تم تعديل هذه المشاركة بواسطة المشتاقة للرحمن في 4 ديسمبر 2009 في 17:51
@ بالنسبة للسؤال : هل تعتبر boundary fill هي seed algorithm ، سؤال أكاديمي لا أعرف له جواب ، لكن واضح أن boundary fill هي قريبة من flood fill حيث كلاهما يبدآن من seed معيّن ( بذرة ) ، ولكن الفرق بينهما هو شرط التوقف فقط .
@ شكراً على التصحيح ( حيث كتبته على عجل ، لكن المهم أن التطبيق يعمل ، بالنسبة لطباعة المصفوفة فهي غير مهمة وللتوضيح فقط ) .
الأسئلة في المرفقات كانت عن هذه الدوال :
void reshape(int w,int h)//شرح بسيط للدالة
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,w,0,h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}هذه من أساسيات OpenGL ، يتم استدعائها عند تغير حجم النافذة ( وعند انشاء النافذة) ، حيث نحدد ثلاثة أمور :
1- منفذ الرؤية ، View port ، أي أين سنرسم ، وقد طلبت أن أرسم على كامل النافذة ( من الزاوية اليسرى السفلية الى الزاوية العلوية اليمنى ) حيث w تعني عرض النافذة و h تعني طول النافذة .
2- نحدد مصفوفة الاسقاط عن طريق GL_PROJECTION ، بحيث أي تغييرات نجريها ستؤثر على مصفوفة الاسقاط ، المصفوفة التي أنشأتها هي مصفوفة اسقاط عمودية باستخدام gluOrtho2D ، حيث هذا النوع من الاسقاط يصلح للتطبيقات ثنائية البعد .
3- حددت مصفوفة MODELVIEW وبالتالي أي تغييرات نجريها ستؤثر على MODELVIEW ، وهي تؤثر على View ( أي الكاميرا ان صح التعبير ) و Model أي المجسم ، أنا جعلت المصفوفة ، مصفوفة وحدة ، وبالتالي سيدأ الرسم من الزاوية اليسرى السفلية ( صفر ، صفر ) ، وهي نقطة الأصل بالنسبة لـ OpenGL ، ويمكن تغيير هذه النقطة من خلال gluOrtho2D.
راجعوا قسم OpenGL للمزيد .
الدالة الثانية :
void drawImage()//لم افهم الدالة جيدا
{
int width = (IMAGE_WIDTH/CELL_NUMBER);//العرض للبكسل تبع الحد؟
int height= (IMAGE_HEIGHT/CELL_NUMBER);//الطول للبكسل تبع الحد؟
int xPos = 0, yPos = IMAGE_HEIGHT- (height-CELL_NUMBER);//لماذا افترضنا هذه القيم؟؟
for(int x=0;x<CELL_NUMBER;x++)
{
for(int y=0;y<CELL_NUMBER;y++)
{
if(getPixel(x,y)==BLACK)
glColor3f(0,0,0);
else if(getPixel(x,y)==WHITE)
glColor3f(1,1,1);
else if(getPixel(x,y)==RED)
glColor3f(1,0,0);
else
glColor3f(0.1f,0.1f,0.7f);
// الغرض من اللوب
glRectf(xPos,yPos,xPos+width,yPos + height);//اتمنى تشرح هذه النقطة و التي تليها
xPos+= width + 1;
}
xPos= 0;
yPos-= (height + 1);
}
}الغرض منها طباعة المربعات ( البكسلات ) ،
حيث نعمل loop على مصفوفة ، وبما أن المصفوفة مصفوفة ثنائية ، عملت loop داخل loop ، للتسهيل فقط .
المتغيرات والثوابت هي كالتالي :
IMAGE_WIDTH : عرض النافذة == عرض الصورة ، أنا سميتها صورة فقط للتوضيح ، يعني ممكن تسميتها WINDOW_WIDTH ، ونفس الكلام ينطبق على IMAGE_HEIGHT
CELL_NUMBER : عدد المربعات في طل صف وعمود ، أنا جعلتها 10 مربعات .. يمكن تغييرها .
width : عرض كل مربع بالبكسل ، يمكن أن تختاري أي عرض ، لكن وحتى أملأ النافذة بالمربعات ولاتظهر فراغات ، عملت معادلة بسيطة :
height : نفس الكلام مع width ولكن هنا طول المربع ، وبما أن طول النافذة مثل عرضها ، وعدد المربعات العرضية مثل عدد المرعات الطولية ، فالنتيجة واحدة وهي 40 بكسل.
xPos: الحد الأيسر للمربع .
yPos : الحد السفلي للمربع .
أخيراً نعمل loop على المصفوفة ( حيث x يبدأ من صفر الى 9 ، اي عشر لفّات) ونفس الامر مع y ، وكل مرة نغير اللون بناء على قيمة كل عنصر من المصفوفة : أسود - أبيض - أحمر ، وهي مجرد ثوابت للتسهيل .
ونرسم المربع باستخدام glRect ، حيث أول بارمترين هما النقطة السلفية للمربع xPos,yPos ، والبارمترين الاخيرين طول وعرض المربع .
ثم في كل loop داخلي : أزيد xPos بقيمة تساوي عرض المربع + 1 وذلك حتى نرسم المربع المقبل على يمين المربع الحالي ويكون هناك فراغ بسيط بينهما .. بتغيير القيمة سيتضح الهدف.
ثم عندما ننتهي من كل صف ، أي ننتهي من اللوب الداخلي ، نبدأ سطر جديد yPos -= height + 1 ، و xPos=0 ، أي ننتقل الى السطر التالي ابتداء من أعلى النافذة .
بتغيير القيم سيتضح الهدف ، كما قلت .
void mouse(int b,int s,int x,int invY)//اريد شرح مبسط لداخل الداله
{
if(b == GLUT_LEFT_BUTTON)
{
if(s == GLUT_DOWN)
{
int y = IMAGE_HEIGHT - invY;
int X = min(ceil((float) x / (IMAGE_WIDTH/CELL_NUMBER) + 1),CELL_NUMBER+1);//مالغرض من تلك الدوال؟
int Y = min(ceil((float) y / (IMAGE_HEIGHT/CELL_NUMBER) + 1),CELL_NUMBER+1);
Y-=2;//why?
X-=2;//WHY?
if(X<0 || X> CELL_NUMBER || Y<0 || Y > CELL_NUMBER)
return ;
boundaryFill(X,CELL_NUMBER-1-Y,BLACK,BLUE); //CELL_NUMBER-1-Yلماذا
}
}
glutPostRedisplay();// هل تعيد العرض؟
}- هنا نصطاد نقرة الفأرة ، فاذا نقر بالزر الايسر ، نحاول أن نكتشف أين حدثت النقرة ، على أي مربع .
وحيث أننا نعلم مكان النقرة من خلال x و yInv ،
طبعا يجب ملاحظة أن نظام ويندوز يعتبر نقطة الاصل هي النقطة العلوية اليسرى للنافذة وهذا عكس OpenGL ، لذلك وحتى يتوافق الامر مع OpenGL نكتب التالي :
int y = IMAGE_HEIGHT - invY;
- الامر الاخر ، كيف نعرف أن المستخدم نقر على المربع الثاني العلوي مثلا /
الحل :
نحن نعرف موقع الماوس .. اين نقر ..
فنطبق عليه المعادلة :
int X = min(ceil((float) x / (IMAGE_WIDTH/CELL_NUMBER) + 1),CELL_NUMBER+1);
وهي ليست قانون بالمناسبة .. ولكن يمكن لأي مبرمج أن يفكر بالامر .. لاستنتاج المعادلة المناسبة .
حيث يمكن أن نبسطها هكذا :
int X = x / (IMAGE_WIDTH/CELL_NUMBER) + 1;
الان نعود الى مثالنا ..
// اذا نقر على البيكسل ذو الاحداثي // x = 120 , y = 240 myX = 120/ ( 400 / 10 ) = 120/40 = 3; myY = 240/ ( 400/ 10 ) = 240/40 = 6; // الان .. نعرف أي عنصر من المصفوفة تم اختياره // وهو العنصر التالي : // image[myX][myY] = image[3][6] = 1 // الان نستدعي الخوارزمية لتبدا من هذا العنصر كبذرة
بالنسبة للدالة glutPostRedisplay فهي لتحديث الرسم .. لو تم ازالتها لن تحدث النافذة الا اذا تم تحريكها فوق نافذة اخرى مثلا ..
يمكن استبدال glutPostRedisplay باستدعاء دالة الرسم مباشرة display ..
أتمنى أن الامور واضحة الان .
الحمدلله .
تم تعديل هذه المشاركة بواسطة الشمري في 5 ديسمبر 2009 في 01:00
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri
رعاك الله و وفقك
جربت ارسل قيمة Y
بدون boundaryFill(X,CELL_NUMBER-1-Y,BLACK,BLUE); //CELL_NUMBER-1-
لكن الداله لم تلون
فرج الله عنك رفع قدرك و منزلتك في عليين على هذه المساعدة الطيبة
وعذرا لكثرة استفساراتي لأني احب ان افهم وان تم التطبيق بشكل صحيح
سأقول شيء للفائدة :
لايلزم على أي مبرمج أن يفهم بالظبط ماكتب الاخر ، في الأمور الثانوية ، فلكل مبرمج طريقته ، وما أنتجه تفكيره ( أتكلم هنا عن الخوارزميات والمعادلات وليس عن تنظيم الكود ) ،
أواجه شخصياً مشاكل مع بعض الخوارزميات والمعادلات من أين أتت .. بمجرد أن أحاول أن أحلها بنفسي ، أجد أنّي أسلك نفس الطريق الذي سلكه غيري ، وبالتالي تجد أنه وفي كثير من الاحيان ، الكود يتشابه مع كود اخر في فكرة الحل ، حتى وان لم يقتبس أحدهما من الاخر .
نعود :
سبب كل هذه المعادلات التي رأيتي ، هي مشكلة واحدة غبية ، كنت أحاول أن أتمسك بها .. وهي :
في OpenGL : نقطة الاصل في الزاوية اليسرى السفلية .
في Windows : نقطة الأصل في الزاوية اليسرى العلوية .
ولذلك رأيتي تلك المعادلات ووجع الرأس ..
الان قمت بتحويل نظام الاحداثيات في OpenGL الى النظام التقليدي في الويندوز :
//سابقا gluOrtho2D(0,w,0,h); // الان gluOrtho2D(0,w,h,0);
وبسبب هذا التغيير البسيط .. لن يرا أحد أي معادلة أو وجع رأس .. اختفى كل شيء :) .
لا أعرف لماذا أحب أن أتفلسف حياناً .
المعذرة على الصداع الذي سببته :D .
في المرفقات نسخة جديدة ، سأحدث المشاركات السابقة أيضاً .. ان شاء الله .
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri
الآن أصبخت المسألة جدا يسيرة
![]()
سدد الله خطاك
لدي استفسار بسيط بعض الاكواد تبدأ التلوين من اليسار و بعضها من اليمين
اعتقد جميعا تؤدي الى روما ولكن ترتيب التلوين للبكسلات يختلف
فما هو الأفضل نبدا من اليسار او اليمين؟؟
لايوجد فرق كما أعرف
بالتوفيق ..
تطبيق طمأنينة ، نسخة بيتا على أندرويد
عبدالله الشمّري - Al-Shammari
twitter @abshammeri
abshammeri AT gmail.com
github : abshammeri