เมื่อผมเข้ากรุงไปงาน #petdotalkshow

วันนี้ไปงาน #petdotalkshow จัดโดยคุณ @rawitat มาครับ รายละเอียดของงานดูได้ ที่นี่ เป็นงานที่ดีมากๆ เลยงานหนึ่ง และผมโดยส่วนตัวแล้วเป็นคนชอบฟังพวกทอร์คโชว์ด้วย ก็เลยซื้อบัตรแบบไม่ลังเล งานนี้เลยโฉบเดี่ยว

เกริ่นสักหน่อย.. ผมได้ติดตามการ์ตูน #petdo มาแบบอ่านบ้าง ไม่อ่านบ้าง แต่ก็พอคิดได้ว่าเป็นการ์ตูนที่สะท้อนถึงประสบการณ์การทำงานในด้าน IT ได้อย่างเห็นภาพและตรงประเด็น ไม่ใช่แค่เอาฮาอย่างเดียว แต่ก็สามารถเป็นแง่คิดสอนอะไรผมหลายๆ อย่าง และคิดว่าจะมีประโยชน์ต่ออาชีพการงานของผมในอนาคต (ผมยังเรียนอยู่และไม่เคยทำงานแบบเต็มเวลามาก่อน :D) ใครอยากลองอ่านก็เชิญที่ iampetdo.com ครับ

Continue reading "เมื่อผมเข้ากรุงไปงาน #petdotalkshow"

How to install OpenCV 2.1 on Ubuntu

The new version of OpenCV's changed the way to install by using cmake. I also have to update myself and find some information regarding it. Recently, I've read the tutorial on installing OpenCV 2.1 in Ubuntu which explains very well; so, I follow this tutorial and I would note my installation steps here.

  1. install dependencies as follows (please also see the screen shots below).
    • libcv4
    • libcv-dev
    • libcvaux4
    • libcvaux-dev
    • libhighgui4
    • libhighgui-dev
    • opencv-doc (optional)
    • ffmpeg (optional; if you want to use ffmpeg to do video processing)

    check-opencv-packages01

    check-opencv-packages02

  2. install cmake using the command sudo apt-get install cmake.
  3. run cmake -D WITH_FFMPEG=ON -D CMAKE_INSTALL_PREFIX=${HOME}/opencv/ ..
    • Note that there is a dot at the end of the command above which means to run at the current directory.
    • The options mean to use ffmpeg and to set the OpenCV path in your home directory.
  4. check if ffmpeg is available and the folder to install is correct. See the screen shot below.

    config-checking

  5. run the command make
  6. run the command sudo make install.
  7. The last thing is to is to tell the dynamic linker where the DLLs are; so, add the line: export LD_LIBRARY_PATH=${HOME}/opencv/lib to ~/.bashrc and then relogin.

finish.. 🙂

การใช้ OpenCV สร้างกราฟ Histogram จากรูป

บล็อกนี้ผมขอเสนอวิธีใช้ฟังก์ชั่นจาก OpenCV สร้างกราฟ Histogram จากค่าสีที่ได้จากรูปที่เป็น Grayscale นะครับ ซึ่งก็สามารถนำไปประยุกต์ใช้กับรูปที่เป็น RGB หรือ HSV ได้เหมือนกันครับ

ก่อนอื่นเลย Histogram ของรูป คืออะไร.. มันก็คือกราฟที่เกิดจากการพลอตจำนวนของ pixel ที่ค่าสีนั้นๆ นั่นเอง แกน X คือค่าของสี ส่วนแกน Y คือจำนวนของ pixel (อ่านเพิ่มเติมได้ที่ Image histogram ครับ)

เมื่อเราทราบหลักการของการสร้าง Histogram จากรูปแล้ว เราก็มาดูที่โค้ดกันครับ เริ่มต้นเราก็ประกาศขนาดของ Histogram ครับ ให้มีขนาด 256 ช่อง (ค่าสีปกติจะมีค่าระหว่าง 0-255 ในที่นี้ผมจะให้ช่องหนึ่งคือค่าสีหนึ่งนะครับ ซึ่งค่านี้สามารถเปลี่ยนแปลงได้แล้วแต่งานครับ)

int bins = 256;
int hsize[] = { bins };

ในโค้ดของผมนี้ผมจะสร้าง Histogram ที่เป็น uniform นะครับ เราก็ต้องกำหนดขอบเขตของค่า x ซึ่งต้องกำหนดตาม format ดังนี้ครับ โดย ranges[] จะต้องมีจำนวน dimension เท่ากับจำนวนค่าที่เป็นคู่ที่เราประกาศไว้ (คู่ 0 กับ 255)

float xranges[] = { 0, 255 };
float* ranges[] = { xranges };

เนื่องจากรูปตัวอย่างเป็น RGB เราก็ต้องแปลงให้เป็น Grayscale ก่อนนะครับ โดย image ในที่นี้คือรูปที่เราโหลดมาตั้งแต่ต้นนะครับ

IplImage* gray = cvCreateImage( cvGetSize( image ), 8, 1 );
cvCvtColor( image, gray, CV_BGR2GRAY );

จากนั้นเราต้องสร้างเพลน (plane) เพื่อมาคำนวณกราฟกันครับ ในที่นี้มีแค่ 1

IplImage* planes[] = { gray };

แล้วเราก็คำนวณค่าของ Histogram ดังนี้ โดยค่า 1 ตัวแรกหมายถึง จำนวน dimension ครับ ส่วน CV_HIST_ARRAY หมายถึงให้ type เป็นชนิด array และค่า 1 ตัวสุดท้ายหมายถึงว่าเป็น uniform ครับ

CvHistogram* hist = cvCreateHist( 1, hsize, CV_HIST_ARRAY, ranges, 1 );
cvCalHist( planes, hist, 0, NULL );

ในการคำนวณโดยใช้ cvCalHist นั้น เราเซตค่าที่ 3 ว่าให้เป็น 1 แปลว่า ถ้าสมมุติว่าเราวนลูปอ่านค่าสีจากรูปมาเรื่อยๆ เราสามารถบวกค่า pixel เพิ่มได้ในกราฟ Histogram อันเดิมครับ แต่ถ้าเป็น 0 ก็แปลว่าไม่ต้องบวกเพิ่ม ส่วนค่าสุดท้าย ถ้าไม่ใช่ NULL เราจะนำแค่จุด pixel ที่ไม่ใช่ 0 และมีการ mask ไว้ในรูปมาคำนวณครับ

ขั้นตอนต่อไป เราก็ต้องสร้างรูปขึ้นมาเพื่อแสดงผลครับ ในที่นี้เรากำหนดให้มีความสูงแค่ 50 พอครับ

IplImage* imgHistogram = cvCreateImage( cvGetSize( bins, 50 ), 8, 1 );
cvRectangle( imgHistogram, cvPoint( 0, 0 ), cvPoint( 256, 50 ), CV_RGB( 255, 255, 255 ), -1 ); // ค่าสุดท้ายคือค่า thickness ครับ ถ้าเป็น -1 แสดงว่าให้เป็นค่าสูงสุดเลย (เพื่อที่ว่าเราจะระบายสีขาวให้เต็มสีเหลี่ยมเลยครับ)

ขั้นตอนสุดท้ายเราก็วาดกราฟครับ และแสดงผล วิธีการก็คือดึงค่าออกมาทีละค่านั่นเอง แต่เนื่องจากเราเซตความสูงไว้ที่ 50 เราจะต้อง normalize ด้วยนะครับ แต่การที่เราจะ normalize ได้เราต้องมีค่าสูงสุดของ Histogram ก่อนครับ หาได้ดังนี้

float max_value = 0, min_value = 0;
cvGetMinMaxHistValue( hist, &min_value, $max_value );

และสุดท้ายจริงๆ ก็ดังนี้ครับ

cvNamedWindow( "histogram", 1 );
for( int i = 0; i < bins; i++ ) {
  float value = cvQueryHistValue_1D( hist, i );
  int normalized = cvRound( value * 50 / max_value );
  cvLine( imgHistogram, cvPoint( i, 50 ), cvPoint( i, 50 - normalized ), CV_RGB( 0, 0, 0 ) );
}
cvShowImage( "histogram", imgHistogram );

หวังว่าจะเป็นจุดอ้างอิงสำหรับผู้ที่เริ่มต้นสนใจในด้าน Image Processing นะครับ

Source code: hist.cc

credit: Isaias Gonzalez (siderevs at gmail dot com)

เก็บโน้ต TomBoy ของคุณให้ sync กับเครื่องอื่น โดยใช้ Dropbox

เรื่องของเรื่องก็คือ ผมอยากจะเปลี่ยนไปใช้ Ubuntu เต็มตัว และใช้ Windows เฉพาะเล่นเกม (DotA) และเรื่องที่สำคัญอย่างหนึ่งก็คือผมเก็บโน้ตของผมไว้ใน MS OneNote และ sync กันระหว่างเครื่องโดยใช้ LiveMesh ซึ่งถ้าผมเปลี่ยนไปใช้ Ubuntu ผมก็ต้องการ feature แบบนี้เช่นกัน

วันนี้ผมได้วิธีง่ายๆ มาและอยากแบ่งปันก็คือใช้ Tomboy Notes และ Dropbox นั่นเอง ถึงแม้ว่า Tomboy จะดีไม่เท่า OneNote ก็ตาม แต่ผมก็ยังคงไม่มีปัญหา เพราะเดิมที ไม่ได้ใช้ความสามารถของ OneNote มากสักเท่าไหร่

วิธีทำให้โน้ตของเรา sync กับ Dropbox ก็ให้ไปที่ Tomboy แล้ว Edit -> Preferences -> Synchronization และ ใช้ Service เป็น Local Folder จากนั้นก็เซต Folder Path ให้อยู่ภายใต้โฟลเดอร์ของ Dropbox และตามด้วยชื่อโฟลเดอร์ที่เราต้องการ เช่น ~/Dropbox/Tomboy หลังจากนั้น เราก็เขียนโน้ตตามปรกติ ถ้าเราต้องการให้ sync กัน ให้เลือกที่ Tools -> Synchronize Notes

เป็นอันเสร็จสิ้น 🙂

credit: http://www.starryhope.com/linux/2009/synchronize-tomboy-notes-with-dropbox/

แนะนำการใช้ Perl เพื่อหาผลการทดลอง

เวลาที่เราเขียนโปรแกรมแยกกัน เราจะทำผลการทดลองแบบ manual หรือแบบที่เรารันโปรแกรมทีละขั้นตอน เพื่อเอาผลจากขั้นตอนหนึ่งไปยังอีกขั้นตอนหนึ่ง ซึ่ง ปัญหาที่ผมได้พบจากประสบการณ์โดยตรง คือ "ใช้เวลามากเกินไป" และ "ผิดพลาดได้ง่าย" ซึ่งหลายคนอาจจะคิดเหมือนผมที่ว่า เราเขียนโปรแกรมเสร็จแล้ว เราก็แค่ใส่ค่า ใส่ข้อมูล แล้วเราก็ได้ผลออกมา ไว้ทำทีหลังละกัน..

ซึ่งเป็นความคิดที่ไม่ค่อยจะถูกนักครับ ตอนที่เราทดลองเราจะพบปัญหาอีกมากมาย เช่น ผลที่ได้ไม่ดีนัก เราต้องทำใหม่อีกรอบ และเราก็อาจจะ ไม่มีทางรู้ได้ว่าโปรแกรมทำงานผิด หรือว่าเราใส่ข้อมูลผิดหรืออะไรก็แล้วแต่ ยิ่งถ้าใกล้เวลาส่งงานเมื่อไหร่แล้ว เราจะยิ่งลน และทำให้เกิดความผิดพลาดได้ง่ายมากๆ

บล็อกนี้ผมขอแนะนำการใช้ Perl ครับ ในกรณีของผม ผมใช้ Perl script ไฟล์เดียว ใส่ค่าพารามิเตอร์ครั้งแรก เราก็แค่รอให้ผลออกมา ถ้าไม่ดี เราก็รันคำสั่งเดียว เปลี่ยนค่าพารามิเตอร์ และก็รอผล ก็ดูง่ายๆ ใช่เปล่าครับ แต่สำหรับคนที่ไม่เคยทำ และจะลองมาทำดูก็จะค่อนข้างเสียเวลาในการศึกษา เสียเวลาไป google หาโค้ด หาตัวอย่าง ผมเลยเอาโค้ดที่ผมคิดว่าใช้บ่อยๆ มารวมไว้ครับ

ก่อนที่จะใช้ Perl script ผมแนะนำให้

  1. เขียนโปรแกรมให้รับค่าพารามิเตอร์จาก command line ให้ได้ก่อน ถ้าเป็นภาษา C/C++ ก็ใช้พวก argc, argv และ getopt (ลองดูโค้ดตัวอย่างได้ที่  ตัวอย่าง getopt ครับ
  2. ตอนที่แสดงผลจากโปรแกรมนั้น ให้เราแสดงออกมาทาง stdout หรือจะเขียนลงไฟล์ก็ได้ครับ
  3. output ที่ออกมา เราควรจะออกแบบสักหน่อย เพื่อให้โปรแกรมต่อไปสามารถรับจาก command line ได้

ต่อไปนี้ก็จะเป็นโค้ดตัวอย่างที่ผมใช้บ่อยๆ ครับ

การรับพารามิเตอร์จาก command line ใช้ดังนี้

my $myVariable = $ARGV[0];

เริ่มจากเลข 0 ครับ ถ้ามี 3 ค่า จะเป็นดังนี้

my $myVariable1 = $ARGV[0];
my $myVariable2 = $ARGV[1];
my $myVariable3 = $ARGV[2];

ส่วนคำสั่ง Perl สำหรับรันโปรแกรมที่เราเขียนขึ้นเองต่างหากก็ตามนี้

system( "myProgram $param01 $param02" );

เปิดโฟลเดอร์เพื่อแสดงชื่อไฟล์ทั้งหมด (รวมทั้งชื่อโฟลเดอร์ด้วย ฉะนั้นแนะนำว่าให้ชื่อไฟล์มี extension ไว้ แล้วแก้คำสั่ง grep เพื่อกรองเอาแต่ไฟล์ครับ)

opendir( DIR, $folder_name ) or die "couldn't open $folder_name\n";
# ไม่เอา . ไม่เอา .. และไม่เอา .svn (เผื่อว่าเราใช้ svn)
my @files = grep { $_ ne '.' && $_ ne '..' && $_ ne '.svn' } readdir DIR;
for $file ( sort @files ) {
  print $file . "\n";
}

ถ้าต้องการที่จะเรียงไฟล์ตามตัวอักษรไม่ใช่ตามแบบ string ก็ใช้ตามนี้ครับ

for $file ( sort { $a <=> $b } @files ) { ... }

ส่วนฟังก์ชั่นตัด extension ของไฟล์

sub without_ext {
  my ( $file ) = @_;
  return substr( $file, 0, rindex( $file, '.' ) );
}

วิธีใช้ก็แค่โยนชื่อไฟล์เข้าไปแบบนี้ without_ext ( $file )

และฟังก์ชั่นตัดเอามาแต่ extension ของไฟล์

sub ext_only {
  my ( $file ) = @_;
  return substr( $file, rindex( $file, '.' ) + 1 );
}

วิธีใช้ก็แค่โยนชื่อไฟล์เข้าไปแบบนี้ ext_only( $file ) เช่นกัน

การเปิดไฟล์สำหรับอ่านและการอ่านไฟล์

open( FILE, $filename ) or die( "Cannot open file" );
@data = <FILE>;
foreach $text_line ( @data ) {
  print $text_line . "\n";
}

การเปิดไฟล์สำหรับเขียนลงไฟล์ก็แค่เพิ่ม ">" ลงไปก่อนหน้าชื่อไฟล์ครับ ดังนี้

open( FILE, ">$filename" ) or die( "Cannot open file" );
print FILE "test\n";

การอ่านข้อมูลจาก stdout

# ต้องใส่ | ข้างหลังด้วย แปลว่าให้อ่านจาก pipe
open( OUTPUT, "myProgram $param01 $param02 |" );
while( <OUTPUT> ) {
  # แบบนี้จะตัด input โดยใช้การขึ้นบรรทัดใหม่เป็นตัวกำหนด ถ้าต้องการตัดโดยใช้ tab ก็เปลี่ยนจาก "\n" เป็น "\t"
  @output = split( "\n", $_ );
  foreach $val ( @output ) {
    print $val . "\t";
  }
}

สามารถหาข้อมูลเพิ่มเติมเกี่ยวกับ open() ได้ ที่นี่ ครับ

หวังว่าจะมีประโยชน์สำหรับหลายๆ ท่านนะครับ 🙂