روباتيک و پردازش تصوير- ( قسمت 4)
در مثال هايي كه پيش روي خواهيم داشت، علاوه بر جذاب بودن آنها، تمامي مفاهيم پردازش تصوير را بصورتي مملوس از نظر خواهيم گذراند. در پايان اين مقاله شما مقوله پردازش تصوير را تماما درك نموده و با ابزارهاي آن آشنايي پيدا خواهيد نمود.
در اينجا مناسب مي دانم كه نيم نگاهي به برنامه بيندازيم تا با متد فعاليت، آشنايي لازم را كسب نموده و مراحل برنامه را بصورت سليسی دنبال كنيم. بمنظور مرور بخش هاي گذشته، مراحلي را كه مي بايست انجام گيرند با هم مرور مي كنيم.
به شكل 1 كه برنامه آموزشي ما با آن شروع مي شود، توجه كنيد .

شكل 1 : رابط گرافيگي برنامه الگو
با اجراي برنامه، فايل تصويري "Sample.bmp" بصورت پيش فرض در قسمت Original Image نشان داده مي شود. بعد از نوشتن متن محرمانه خود در قسمت Secret Message و زدن دكمه Encode، متن نوشته شده در درون تصوير جاسازي شده، و تصوير حامل متن در قسمت Image With Text قابل مشاهده است. بعد از اين كار، در صورتيكه دکمه Decode را فشار دهيد، متن جاسازي شده در تصوير، در قسمت Decoded Message نمايش داده مي شود.



شكل 2 : مراحل كار از بالا به پايين
حال كه با شيوه كار برنامه آشنا شديد، عملياتي را كه در اين برنامه انجام مي شود مرورمي كنيم.
مراحل و عملياتی كه با فشار دادن دكمه Encode انجام مي پذيرد:
• تبديل حروف نوشته شده در قسمت Secret Message به قالب کدهای ASCII
• قرار دادن كد اسكي معادل هر كاراكتر در خانه هاي آرايه اي بنام letters.
• تقسيم كاراكترها به قسمتهاي دو بيتي و قرار دادن هر دو بيت در يكي از خانه هاي آرايه dividedLetters بصورت جداگانه
• توزيع دو بيتي ها در دو بيت كم ارزش هر يك از بايتهاي تصويري (هر پيكسل توانايي ذخيره سه قسمت دو بيتي را در خود دارد، يعني شش بيت)
نكته : هنگام استخراج اطلاعات از تصوير، مي بايست تعداد پيكسل هايي كه اطلاعاتي در آنها ذخيره شده است مشخص شده باشد. براي اين كار شيوه اي را كه خود برگزيدم، اين است كه تعداد كاراكترهاي مورد نظر را در پيكسل های اول تصوير ذخيره مي نمايم تا قبل از شروع عمليات استخراج مشخص شود كه پردازش پيكسل ها را تا كجا بايد ادامه داد. در غير اينصورت مي بايست تا آخرين پيكسل فايل تصويري حركت نمود كه علاوه بر اتلاف زمان هيچگونه فايده اي نيز ندارد. شيوه ديگري را كه مي توان در نظر گرفت اين است كه بعد از جاسازي متون در تصوير و جاسازي آخرين دو بيت، در آخرين پيكسل، تعدادی از پيكسل هاي بعدي را علامت گذاري نمود كه اين شيوه توصيه نمي شود، زيرا ممكن است علامت گذاري ها با اصل متن تداخل ايجاد كنند.
همانطور مشاهده خواهيد نمود کدهای زير مربوط به محاسبه تعداد كاراكترها، تعداد پيكسل هاي مورد نياز براي ذخيره آنها و چگونگي تقسيم هر يك ار كاراكترها به چهار دو بيتي و قرار دادن آنها در آرايه اي جديد است. ابتدا نمونه ای از مجموع عمليات اشاره شده را از نظر مي گذرانيم، سپس هر قسمت را جداگانه مورد بررسی قرار می دهيم.


جدول 1
حال لطفا به توضيحات خط به خط كدها توجه نماييد. اما قبل از آن مجددا به اين نكته اشاره مي كنم كه سعي نماييد تفاوت هاي ميان دو زبان بکار رفته را بمنظور آشنايي و استفاده از هر دو زبان مورد توجه قرار دهيد.
• در كدهاي زير، تعداد اوليه كاراكترها بصورت مبناي هشت در سه خانه اول آراية letters ذخيره مي شوند.
C++ Builder
letters[0] = (int)( len / (256*256) );
letters[1] = (int)( (len % (256*256)) / 256 );
letters[2] = (int)( (len % (256*256)) % 256 );
letters[0] := len div (256*256);
letters[1] := (len mod (256*256)) div 256;
letters[2] := (len mod (256*256)) mod 256;
در كدهاي ذيل، حلقه استفاده شده، كليه كاراكتر هاي متني را در آرايه letters و بعد از سه خانة اول قرار مي دهد.
C++ Builder
for (int i = 1; i <= len; i++)
{
String singleChar = secretM.SubString( i, 1);
letters[i+2] = (int)singleChar[1];
}
for i := 1 to len do
begin
singleChar := copy( secretM, i, 1);
letters[i+2] := ord(singleChar[1]);
end;
• در كدهاي زير، عدد 3 به متغيير len كه نشاندهنده تعداد خالص كاراكترها است، اضافه مي شود. اين سه خانه بمنظور ذخيره سازي تعداد كاراكترها در نظر گرفته شده اند.
C++ Builder
len = len + 3;
len := len + 3;
• از آنجا كه در برنامه، هر يك از پيكسل ها بصورت كامل (هر سه بايت) مورد بررسي قرار مي گيرند، بنابراين تدابيري انديشه شده تا تعداد دو بيتي هاي استفاده شده در فايل تصويري، مضربي از سه و چهار باشد. (بدليل اينكه هر پيكسل از سه بايت تشكيل شده است، بنابراين از سه تا دو بيتي استفاده مي نمايد و اينكه هر كاراكتر از هشت بيت تشكيل شده است و به چهارتا دو بيتي تبديل مي شود). در كدهاي خطوط زير، تعداد كاراكترها به گونه اي تعيين مي شود كه تعداد بيت هاي مورد استفاده مضربي از سه و چهار باشد (كاراكتر فاصله يا Space در صورت نياز به آخر كاراكترها افزوده مي شود). در نهايت تغييرات اعمال شده در خانه شماره سه يا letters[2] به روز مي شود.
C++ Builder
int diff = (len*4) % 3;
for ( int i = 1; i <= 3-diff; i++ )
letters[len+i-1] = 32;
len = len + (3-diff);
letterNo = len;
letters[2] = letters[2] + (3-diff);
diff := (len*4) mod 3;
for i := 1 to 3-diff do
letters[len+i-1] := 32;
len := len + (3-diff);
letterNo := len;
letters[2] := letters[2] + (3-diff);
• در كدهاي ذيل، كاراكترها و نشانگرهاي موجود در آرايه letters به قسمت هاي دو بيتي تقسيم شده (هر كاراكتر به چهار قسمت تبديل مي شود) و در خانه هاي آراية dividedLetters جاي مي گيرند.
C++ Builder
for ( int i = 0; i <= len-1; i++ )
{
dividedLetters[4*i] = divideLetter(letters[i], 0);
dividedLetters[4*i +1] = divideLetter(letters[i], 1);
dividedLetters[4*i +2] = divideLetter(letters[i], 2);
dividedLetters[4*i +3] = divideLetter(letters[i], 3);
}
for i := 0 to len-1 do
begin
dividedLetters[4*i] := divideLetter(letters[i], 0);
dividedLetters[4*i +1] := divideLetter(letters[i], 1);
dividedLetters[4*i +2] := divideLetter(letters[i], 2);
dividedLetters[4*i +3] := divideLetter(letters[i], 3);
end;
حال كدهايی را كه مربوط كه چگونگي جاسازي دو بيتي ها در پيكسل هاي تصوير مورد نظر است، مورد بررسي قرار مي دهيم:
• پس از تعريف و مقدار دهي اوليه متغيرهاي pixelCounter و blockCounter و بارگذاري متغير BitMap با تصويري بنام Sample.bmp، وارد مرحله آزمايش امكان يا عدم امكان جاسازي متون نوشته شده با تصوير مي شويم. در صورتيكه متن زياد و تصوير كوچك باشد، پيغام خطايي نمايش داده مي شود و مراتب را به اطلاع كاربر مي رساند.
C++ Builder
int pixelCounter = 0;
int blockCounter = 0;
Graphics::TBitmap *BitMap = new Graphics::TBitmap();
Byte *P;
try
{
BitMap->LoadFromFile("sample.bmp");
if ( letterNo*4 > (BitMap->Height*BitMap->Width*3) )
{
ShowMessage( "The Image cannot be loaded with this amount of text. Sorry!" );
Application->Terminate();
}
…
pixelCounter := 0;
blockCounter := 0;
BitMap := TBitMap.create;
try
BitMap.LoadFromFile('sample.bmp');
if ( letterNo*4 > (BitMap.Height*BitMap.Width*3) ) then
begin
ShowMessage('The Image cannot be loaded with this amount of text. Sorry!');
Application.Terminate;
end;
…
• حلقه هاي تو در توي y و x تمامي مراحل جاسازي را انجام مي دهند. فرمان ScanLine تمامي پيكسل هاي موجود در خط y را در متغيير p قرار مي دهد. سپس پردازش هاي مورد نياز بر روي پيكسل ها درون حلقه x انجام مي گيرد. البته قبل از انجام هر كاري در حلقه x، ابتدا اين مسئله چك مي شود كه تعداد پيكسل هاي پردازش شده از تعداد كاراكترها و نشانگرها تجاوز نكند.
C++ Builder
for ( int y = 0; y <= BitMap->Height-1; y++ )
{
P = (Byte*)BitMap->ScanLine[y];
for ( int x = 0; x <= BitMap->Width-1; x++ )
{
if (letterNo*4 >= pixelCounter)
{
P[3*x] = P[3*x] & 0xFC;
P[3*x] = P[3*x] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
P[3*x+1] = P[3*x+1] & 0xFC;
P[3*x+1] = P[3*x+1] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
P[3*x+2] = P[3*x+2] & 0xFC;
P[3*x+2] = P[3*x+2] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
pixelCounter = pixelCounter + 1;
}
} // end FOR X
} // end FOR Y
for y := 0 to BitMap.Height -1 do
begin
P := BitMap.ScanLine[y];
for x := 0 to BitMap.Width -1 do
begin
if (letterNo*4 >= pixelCounter) then
begin
P[3*x] := P[3*x] and $FC;// data;
P[3*x] := P[3*x] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
P[3*x+1] := P[3*x+1] and $FC;
P[3*x+1] := P[3*x+1] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
P[3*x+2] := P[3*x+2] and $FC;
P[3*x+2] := P[3*x+2] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
pixelCounter := pixelCounter + 1;
end;
end; // end FOR X
end ; // end FOR Y
• حال، ابتدا دو بيت كم ارزشِ هر سه بايت موجود در پيكسل فعلي با استفاده از عملگر AND تبديل به صفر مي شوند سپس اطلاعات مورد نياز در آن دو بيتي ها با استفاده از OR جاسازي مي شوند.
C++ Builder
P[3*x] = P[3*x] & 0xFC;
P[3*x] = P[3*x] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
P[3*x+1] = P[3*x+1] & 0xFC;
P[3*x+1] = P[3*x+1] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
P[3*x+2] = P[3*x+2] & 0xFC;
P[3*x+2] = P[3*x+2] | dividedLetters[blockCounter];
blockCounter = blockCounter + 1;
pixelCounter = pixelCounter + 1;
P[3*x] := P[3*x] and $FC;
P[3*x] := P[3*x] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
P[3*x+1] := P[3*x+1] and $FC;
P[3*x+1] := P[3*x+1] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
P[3*x+2] := P[3*x+2] and $FC;
P[3*x+2] := P[3*x+2] or dividedLetters[blockCounter];
blockCounter := blockCounter + 1;
توضيح تابع divideLetter
اين تابع دو ورودي دارد كه يكي كاراكتر currentLetterو ديگري عددي بين 0 و 3 است. كار تابع اين است كه بعد از گرفتن كاراكتر ورودي، تمامي دو بيتي هاي آن كاراكتر را بجز دو بيتي شماره n (شمارش از چپ به راست) صفر نمايند. سپس آن دو بيتي را بعنوان اولين دو بيتي قرار مي دهيد (توسط shr) و بعنوان خروجي تابع بر مي گرداند. بعنوان مثال اگر كاراكتر (01100100) وعدد 2 ورودي تابع باشد، ابتدا تمامي دو بيتي ها بغير از دو بيتي شماره سه تبديل به صفر مي شوند:
00 10 00 00
سپس با استفاده از شيفت راست، خروجي تابع بصورت زير در خواهد آمد:
00 00 00 10
به کدها توجه نماييد:
C++ Builder
int divideLetter( int currentLetter, int n )
{
int splitPart;
splitPart = currentLetter & (int)( 3*(pow(4,3-n)) );
splitPart = splitPart >> ( 2*(3-n) );
return splitPart;
}
function divideLetter( currentLetter : Integer; n : Integer ) : ® Integer;
var
splitPart : Integer;
begin
splitPart := currentLetter and ( 3*round(power(4,3-n)) );
splitPart := splitPart shr ( 2*(3-n) );
result := splitPart;
end;
• در اينجا بمنظور مشاهده تصويري كه متون محرمانه در آن جاسازي شده است، بكار رفته اند. همچنين خروجي تصويري برنامه نيز با نام SampleWithText.bmp در همان مسيري كه فايل اجرايي قرار دارد، ذخيره مي شود.
C++ Builder
newImage->Height = BitMap->Height;
newImage->Width = BitMap->Width;
newImage->Canvas->Draw(0,0,BitMap);
BitMap->SaveToFile( "SampleWithText.bmp" );
newImage.Height := BitMap.Height;
newImage.Width := BitMap.Width;
newImage.Canvas.draw(0,0,BitMap);
BitMap.SaveToFile( 'SampleWithText.bmp' );
در اين قسمت تنها به نكات جديد موجود اشاره مي نمايم و از اشاره به مطالبي كه قبلا به آنها پرداخته شده صرفه نظر مي كنيم زيرا بسياري از نكات را در قسمت قبل از نظر گذرانديم.
• در اينجا ابتدا فايل تصويري SampleWithText.bmp را در متغيير BitMap بارگذاري مي كنيم.
C++ Builder
BitMap->LoadFromFile( "SampleWithText.bmp" );
BitMap.LoadFromFile('SampleWithText.bmp');
• اينک، ابتدا مقادير جاسازي شده در چهار پيكسل اول را استخراج نموده و هر دو بيت را درون يكي از خانه هاي آرايه usefulBytesForSize قرار ميدهيم (در مجموع اين آرايه از 12 خانه تشكيل شده است و مسئول نگهداری تعداد فايل ها مي باشد)
C++ Builder
for ( int y = 0; y <= BitMap->Height-1; y++ )
{
P = (Byte*)BitMap->ScanLine[y];
for ( int x = 0; x <= BitMap->Width-1; x++ )
if (blockCounter <= 11) // please refer to usefulBytesForSize
{
usefulBytesForSize[blockCounter] = P[3*x];
blockCounter = blockCounter + 1;
usefulBytesForSize[blockCounter] = P[3*x+1];
blockCounter = blockCounter + 1;
usefulBytesForSize[blockCounter] = P[3*x+2];
blockCounter = blockCounter + 1;
}
}
for y := 0 to BitMap.Height - 1 do
begin
P := BitMap.ScanLine[y];
for x := 0 to BitMap.Width - 1 do
if (blockCounter <= 11) then
begin
usefulBytesForSize[blockCounter] := P[3*x];
blockCounter := blockCounter + 1;
usefulBytesForSize[blockCounter] := P[3*x+1];
blockCounter := blockCounter + 1;
usefulBytesForSize[blockCounter] := P[3*x+2];
blockCounter := blockCounter + 1;
end;
end;
• حال از طريق حلقه موجود، مقادير دو بيتي موجود در آرايه مذكور را بصورت كاراكتر در آورده (هشت بيتي) و مقدار عددي را كه در مبناي هشت ذخيره شده است به مبناي ده تبديل مي كنيم و درون متغير letterSize قرار مي دهيم.
C++ Builder
for ( int i = 1; i <= 3; i++ ) // 3 is storage size
{
jointLetters[4*(i-1)] = joinLetter(usefulBytesForSize[4*(i-1)], 0);
jointLetters[4*(i-1)+1] = joinLetter(usefulBytesForSize[4*(i-1)+1], 1);
jointLetters[4*(i-1)+2] = joinLetter(usefulBytesForSize[4*(i-1)+2], 2);
jointLetters[4*(i-1)+3] = joinLetter(usefulBytesForSize[4*(i-1)+3], 3);
if ( i == 1 )
letterSize = 256*256 * ( jointLetters[4*(i-1)] |
jointLetters[4*(i-1)+1] |
jointLetters[4*(i-1)+2] |
jointLetters[4*(i-1)+3] );
else if ( i == 2 )
letterSize = letterSize + 256 * ( jointLetters[4*(i-1)] |
jointLetters[4*(i-1)+1] |
jointLetters[4*(i-1)+2] |
jointLetters[4*(i-1)+3] );
else if ( i == 3 )
letterSize = letterSize + ( jointLetters[4*(i-1)] |
jointLetters[4*(i-1)+1] |
jointLetters[4*(i-1)+2] |
jointLetters[4*(i-1)+3] );
}
for i := 1 to 3 do // 3 is storage size
begin
jointLetters[4*(i-1)] := joinLetter(usefulBytesForSize[4*(i-1)], 0);
jointLetters[4*(i-1)+1] := joinLetter(usefulBytesForSize[4*(i-1)+1], 1);
jointLetters[4*(i-1)+2] := joinLetter(usefulBytesForSize[4*(i-1)+2], 2);
jointLetters[4*(i-1)+3] := joinLetter(usefulBytesForSize[4*(i-1)+3], 3);
if ( i = 1 ) then
letterSize := 256*256 * ( jointLetters[4*(i-1)] or jointLetters[4*(i-1)+1] or
jointLetters[4*(i-1)+2] or jointLetters[4*(i-1)+3] )
else if ( i = 2 ) then
letterSize := letterSize + 256 * ( jointLetters[4*(i-1)] or jointLetters[4*(i-1)+1] or
jointLetters[4*(i-1)+2] or jointLetters[4*(i-1)+3] )
else if ( i = 3 ) then
letterSize := letterSize + ( jointLetters[4*(i-1)] or jointLetters[4*(i-1)+1] or
jointLetters[4*(i-1)+2] or jointLetters[4*(i-1)+3] );
end;
• حال كه تعداد كاراكتر هاي مورد نياز براي استخراج را در دست داريم مي توانيم عمليات را آغاز نماييم. ابتدا تمام دو بيتي هاي موجود در بايتهاي پيكسل را درون خانه هاي آرايه jointLetters قرار مي دهيم. اينكار را با استفاده از تابع joinLetter (كه بعدا به آن اشاره مي نماييم) انجام مي دهيم.
C++ Builder
for ( int y = 0; y <= BitMap->Height-1; y++ )
{
P = (Byte*)BitMap->ScanLine[y];
for ( int x = 0; x <= BitMap->Width-1; x++ )
{
if ( blockCounter <= (letterSize+3)*4 )
{
jointLetters[blockCounter] = joinLetter( P[3*x], blockCounter % 4 );
blockCounter = blockCounter + 1;
jointLetters[blockCounter] = joinLetter( P[3*x+1], blockCounter % 4 );
blockCounter = blockCounter + 1;
jointLetters[blockCounter] = joinLetter( P[3*x+2], blockCounter % 4 );
blockCounter = blockCounter + 1;
}
} // end FOR X
} // end FOR Y
for y := 0 to BitMap.height -1 do
begin
P := BitMap.ScanLine[y];
for x := 0 to BitMap.width -1 do
begin
if ( blockCounter <= (letterSize+3)*4 ) then
begin
jointLetters[blockCounter] := joinLetter( P[3*x], blockCounter mod 4 );
blockCounter := blockCounter + 1;
jointLetters[blockCounter] := joinLetter( P[3*x+1], blockCounter mod 4 );
blockCounter := blockCounter + 1;
jointLetters[blockCounter] := joinLetter( P[3*x+2], blockCounter mod 4 );
blockCounter := blockCounter + 1;
end;
end; // end FOR X
end ; // end FOR Y
• درکدهای خطوط زير كه تمامي دو بيتي ها را در اختيار خود داريم، هر چهار دو بيتي را تبديل به يك كاراكتر مي نماييم و كاراكتر هاي حاصل را پشت سر هم قرار داده تا متن جاسازي شده در تصوير را بصورت كامل مشاهده نماييم.
C++ Builder
for ( int i = 4; i <= letterSize+2; i++ )
// Starting from 4 because the first 3 letters store the size of the message
{
singleChar = char( jointLetters[4*(i-1)] |
jointLetters[4*(i-1)+1] |
jointLetters[4*(i-1)+2] |
jointLetters[4*(i-1)+3] );
m = m + singleChar;
}
MessageMemo->Lines->Add(m);
for i := 4 to letterSize+2 do
// Starting from 4 because the first 3 letters store the size of the message
begin
singleChar := char( jointLetters[4*(i-1)] or jointLetters[4*(i-1)+1] or ®
jointLetters[4*(i-1)+2] or jointLetters[4*(i-1)+3] );
m := m + singleChar;
end;
MessageMemo.Lines.Add(m);
خسته نباشيد! مي دانم كه اين كار براي بسياري از شما كار مشكلي بوده، اما اميدوارم با اجراي برنامه، خستگي كار از تنتان بيرون برود.
به اميد موفقيت...
در صورتيكه با مشكلي در زمينه برنامه نويسي مواجه شديد، مي توانيد سوالات خود را به همراه كد براي اينجانب به آدرس ايميل majidmoh@hotmail.com ارسال نماييد.
پاسخ به سؤالات خوانندگان در زمينه روباتيك
از اينكه بدليل كمبود وقت فرصت پاسخگويي به سؤالات شما عزيزان برايم فراهم نشد از شما پوزش مي خواهم. پاسخ كامل به سؤالات، مناسب تر از اشاره ای کوتاه به نكته است. از آنجا كه سعي مي نمايم پاسخ هاي كوتاه را بصورت مستقيم به ايميل خوانندگان ارسال نمايم، لذا اين قسمت مي تواند پاسخگوي سؤالات رايج ديگر خوانندگان نيز باشد. اميدوارم اينجانب را با پيشنهادهاي خود ياري نموده و در صورتيكه به موضوع خاصي در زمينه روباتيك علاقمند هستيد با ايميل در ميان بگذاريد.
• از مقاله شما چنين بر مي آيد كه شما شخصاً زبان C++ و Delphi را بيشتر از ديگر زبان ها مي پسنديد؟
درست است. اين زبان ها نسبت به ديگر زبان ها از كارايي بالاتري برخوردارند و بازدهي كار برنامه نويس را بالا مي برند. البته اين بدين معنا نيست كه دوستداران ديگر زبان ها بايد مسير خود را تغيير دهند، ولي در صورت امكان شروع آشنايي با يكي از اين دو زبان پيشنهاد مي شود تا هرگاه احساس نياز از مرحله خاصي تجاوز كرد بتوان عمليات سويچ را به انجام رساند.
• آيا تعريف و تمجيد شما (!) از زبان Visual Basic تنها در زمينه روباتيك مصداق دارد يا در ديگر زمينه ها نيز چنين است؟!
همانطور كه در پاسخ به سؤال قبل مطرح شد هر شخصي بسته به علايق شخصي خود و شرايط محيطي مي تواند زبان مورد نظر خود را انتخاب نموده و بر انتخاب خود استوار باشد، اما بنظر اينجانب محصولات شركت Borland، بدليل اينكه كار طراحي و پشتيباني زبان هاي برنامه نويسي را بصورت تخصصي دنبال مي نمايد و از اصول به روز دنيا و آخرين دستاوردهاي آكادميك جهان براي پيشبرد محصولات خود استفاده مي نمايد، مناسبتر از زبان برنامه نويسي محصول شركت مايكروسافت است.
• يكي از سؤالاتي كه تعدادی از دوستان بصورت شخصي مطرح كرده بودند اين است كه آيا رشته رباتيك يك رشته مردانه است و اگر نه، چرا خانم ها وارد گود نمي شوند؟
يكي از بينش هاي غلط و رايج در جامعه، عدم حضور خانم ها در سطح حرفه اي برنامه نويسي است. اين مسئله تنها در ايران شايع نيست، حتي در كشور امريكا و انگلستان خانم ها درصد كمي از برنامه نويسان و كاربران حرفه اي دنياي كامپيوتر را از آن خود كرده اند و تنها تعداد كمي توانسته يا خواسته اند كه از اين مانع عبور نموده و قابليت هاي خود را به اثبات رسانند. خوشبختانه طي سه سال اخير، كشور انگلستان و امريكا با تأسيس اتحاديه اي ويژة خانم ها و مخصوصاً دختران جوان دانشجو، توانسته اند با حمايت و پشتيباني اين قابليت ها، استعدادهاي آنها را شكوفا نمايند (يكي از پيشگامان اصلي اين نهضت مجله ACM امريكايي است. البته اتحاديه مهندسان انگلستان نيز مقالات بسيار جالبي براي جلب نيروهاي آكادميك از ميان فارغ التحصيلان خانم را منتشر نموده است. شما مي توانيد ويژه نامه Women in Computing را از ACM مطالعه نماييد که حاوی مطالب بسيار خواندني از پيشرفت خانم ها در زمينه هاي مردانة (!) كامپيوتر همچون برنامه نويسي و مديريت پروژه است).
متأسفانه در ايران از اين ارگان ها خبري نيست و اگر هست ما از وجود چنين مراكزي بيخبريم و از اين بابت از ما دلگير نشوند زيرا ما نبايد دنبال آنها بگرديم، آنها خود بايد مركز خود را به ديگران بشناسانند!
براي اينكه ما نيز بتوانيم به ميزان مشاركت و علايق خانم ها پي ببريم و همچنين بتوانيم بستر مناسبتری را آغازگر باشيم در شماره هاي آتي بخشي را بعنوان ابتكارات و دستاوردها كه مربوط به روباتيك، پردازش تصوير و غيره باشد بصورت خلاصه همراه نامِ صاحب ايده در مقاله می گنجانيم. اميدوارم در اين بخش خانم ها و مخصوصاً دختران دانشجوي رشتة كامپيوتر و الكترونيك و برنامه نويسان جوان، گوي سبقت را براحتي در اختيار پسران قرار ندهند! در صورتيكه مجله محترم رايانه خبر موافقت نمايد جايزه اي را نيز تقديم بهترين ايده خواهيم نمود.
•آيا در سري مقالات روباتيك درصدد آموزش نحوه استفاده از IC هاي قابل برنامه نويسي و چگونگي ارتباط فيزيكي آن به روبات هستيد؟
اين مسئله به علايق خوانندگان و موافقت مجله بستگي دارد. در صورت مشاهده مثبت بودن اين فاكتورها، فرصتي را به آموزش مقدماتي اين بحث اختصاص خواهيم داد.
•اينكه تمامي روبوت ها به كامپيوتر متصل باشند محدوديت زيادي براي حركت به وجود مي آورد. چه راه حلي پيشنهاد مي كنيد؟
لطفاً به مقاله تير ماه روباتيك، شكل 2 مراجعه نماييد. در آنجا خواهيد ديد كه دو سيستم روباتيك معرفي شده است كه بر اساس شرايط محيطي و نوع كاربرد روبات مورد استفاده قرار مي گيرند.
در روبات مستقل خواهيد ديد كه پردازشگر، جزئي از روبات است كه در كنار عوامل ديگري همچون سنسور و محرك در يك موقعيت و مكان فيزيكي قرار دارند. در اينگونه روبات ها، پردازشگر از نوع IC است كه شرايط محيطي از سنسورها گرفته و بعد از پردازش، فرمان ها را از طريق محرك ها به محيط انتقال مي دهيد.
•به چه دليل ايراني ها در مسابقات روبوكاپ و روباتيك صاحب نام هستند در حاليكه كشور هايي همچون ژاپن، مهمترين محصولات و آخرين دستاوردهاي مربوطه را عرضه مي نمايند؟
جوانان مستعد ما، توانايي هاي خود را هر ساله به اثبات مي رسانند و توانسته اند قدرت مانور خود را در مسابقات دانشگاه هاي جهان در معرض عموم قرار دهند. اما اينكه چرا ژاپن گوي سبقت را در بقيه زمينه ها از ما ربوده، بدين دليل است كه دولتمردان ما تنها به بخش مسابقات روبوكاپ و روباتيك اهميت مي دهند (البته اگر واقعاً اهميت بدهند) و تنها خواسته آنها اين است كه نام كشورمان در سطوح بين المللي درخشش داشته باشد. اين امر نيز مطلوب است.
اما نتيجه :
اولين نتيجه اين سياستگذاري نادرست اين است كه همان جوانان بعد از اتمام تحصيلات خود، براي برآورده نمودن نيازهاي اقتصادي خود، كاري را كه نه چندان باب ميلشان است و از زمينه علاقه آنها فاصله دارد، برمي گزينند و هنگاميكه در جايي بحث و صحبتي از روبوكاپ و روباتيك به گوششان مي رسد تنها به كشيدن آهي از ته دل قناعت مي كنند! البته اين در صورتي است كه آن شخص توسط دانشگاه ها و مراكز علمي جهان دعوت نشده باشد (چون در اين صورت خود براي ديگران آه مي كشد!).
كشورهاي جهان سوم و در حال توسعه، بر خلاف كشورهاي صنعتي، اهميت بيشتري به اعلام نام آنها در تريبون هاي خارجي دارند و بجاي آنكه در فكر جذب سرمايه هاي فكري استعدادهاي خود باشند، در تلاشند آنها را بسوي كسب مقام راهنمايي نموده و بعد از آن خداحافظ! بعنوان مصداق عملي، تنها به گفتن اين مسئله اكتفا مي كنم كه المپيادهاي جهاني معمولا به اين صورت برگزار مي شوند كه افراد بعد از مطالعه شخصي، از فيلتر چند امتحان عبور نموده و وارد مرحله جهاني مي شوند در حاليكه ما براي دانش آموزان و دانشجويان كلاس ها و اردوهاي ويژه برگزار مي نماييمآآآآآ لتبب (يعني آنها را براي المپياد آماده مي سازيم تا مقام بياورند) بعد همان قاعده سابق تكرار مي شود يعني: خداحافظ عزيزان مملكت!!
• در مقالات سابق اشاره اي به سيستم تعادل ربات ها نموده بوديد. آيا ممكن است كمي بيشتر توضيح دهيد؟
در صورتيكه با ابزار تراز كه در بنايي كاربرد دارند آشنا باشيد، مي دانيد كه در صورتيكه حباب تراز در وسط محفظه قرار گيرد نشان دهنده تعادل تراز و افقي بودن سطح است. حال در صورتيكه شيب سطح به سمت راست باشد، حباب درون محفظه به سمت چپ كشيده ميشود و بالعكس. پس ميتوان براي حفظ تعادل از اهرم هاي مكانيكي استفاده نموده و تعادل را در جهت عكس حركت حباب تقويت نمود. توجه داشته باشيد كه مثال ذكر شده تنها براي درك مطلب ارائه شد و در حقيقت از ابزارهاي دقيق ديگري بهره گيري بعمل مي آيد.
• آيا مي توان مطالبي را كه در اينجا ارائه مي نماييد در كتاب خاصي مطالعه نمود؟ لطفاً براي مطالعه بيشتر راهنمايي كنيد؟
همانطور كه قبلاً نيز اشاره نمودم تمامي مقالات سري روباتيك حاصل تجربيات شخصي مي باشد و كتابي كه اين مطالب را ارائه نمايد تاكنون پيدا نكرده ام. شايد اين يكي از دلايل محبوب بودن فوق العاده موضوع روباتيك باشد. اما در صورتيكه عمري باقي باشد اميدوارم بتوانم كتابي را در اين زمينه تأليف نموده و در اختيار علاقمندان قرار دهم تا از ساختن دوباره چرخ جلوگيري نماييم:
"So not to re-invent the wheel!" و شخص بتواند ادامه كار را در دست گيرد نه اينكه از صفر شروع كند و تنها توصيه اي که مي توانم برايتان داشته باشم اين است كه قدرت برنامه نويسي و تحليل خود را افزايش داده و بتوانيد ذهن خود را براي متفكر بودن آماده سازيد. زياد برنامه بنويسيد زياد تغيير دهيد و بي پروا هرچيزي را بيازماييد.
يكي از سوالاتي كه عموميت داشته در خصوص ويژگي هاي فيزيكي روبات ها همچون بزرگي و كوچكي آنها است. علاوه بر اين، نوع عملكرد ربات ها نيز مورد توجه بسياري از خوانندگان جوان و مشتاق مجله بوده كه سعي مي نمايم در شماره هاي آتي علاوه بر پرداختن به موضوعات عملي و برنامه نويسي روباتيك، بخش هايي را به اين موضوع اختصاص دهم.
زندگی قصه: مرد یخ فروشیست