resize + unsharp-mask little by little

Posted by Revolution Wed, 10 Sep 2008 16:01:00 GMT

พี่แสนเคยบอกไว้มานานแล้วว่า เวลาย่อรูปเนี่ยเราไม่ควรย่อลงไปให้ได้ขนาดในทันที เช่น จาก 100% ไปเป็น 50% เราคววรจะแบ่งการย่อทีละนิดๆจาก 100% ไปเป็น 75% แล้วค่อยย่อจาก 75% ให้ได้ 50% หลังการย่อแต่ละครั้งให้ทำ unsharp-mask ด้วยจะทำให้ภาพคมขึ้นและดูสวยงาม
My brother SAN told me long time, when I have to resize, I should not resize to aspect ratio immediately such as 100% to 50%. I have to resize little by little from 100% to 75% then resize from 75% to 50 . Then after each resize process, it should be applied unsharp-mask filter. I will make more sharpen.
ผมก็เลยเขียนเพิ่มให้มันเป็นการแบ่งครั้งที่จะทำการ resize ได้ดังนี้
SHARPEN.times do
                nphoto = photo.resize(NEWSIZE**(1.0/SHARPEN))
                photo = nphoto.unsharp_mask
 end

ดูได้จากภาพตัวอย่าง ได้ที่ multiply

Posted in ,  | Tags , , , ,  | no comments | no trackbacks

Ruby Fork

Posted by Revolution Thu, 04 Sep 2008 16:29:00 GMT

จากครั้งที่แล้วผมอยากจะเขียน ruby สักอันไว้ทำการ stamp ลายเซ็นพร้อมค่า exif ลงในรูป จากการลองเขียนเป็น thread แล้วปรากฏว่าไม่ค่อยมีประโยชน์เท่าไหร่กลับกลายเป็นว่ามี overhead ขึ้นมาเพียบและก็ทำงานไม่ครบได้ทุก core ที่มี งานส่วนใหญ่ในการทำงานเกี่ยวกับภาพนี่จะเป็นในด้านคำนวนซะเยอะ เลยเขียนเป็นลักษณะ fork ออกมาจะดีกว่า
พอลองได้เขียนก็ได้แนวคิดมา 2 แบบ คือ
  • ทำงานแบบเป็น lot คือทำพร้อมกันที่ละเท่าๆกัน แล้วรอให้เสร็จหมด ค่อยเริ่ม lot ต่อไป แบบนี้ถ้ามี process ใน lot เสร็จก่อนเพื่อนก็ต้องรอ
  • แบบที่สองคือเริ่มทำงานให้เต็มตามที่เรากำหนด ถ้า process ไหนเสร็จก่อนก็เอา process ใหม่มา run ได้เลย แบบนี้จะทำให้การทำงานต่อเนื่อง
แบบนี้คือการทำงานแบบเป็น Lot
NUMFORK = 2 
getImg = Dir['*.jpg','*.JPG','*.Jpg','*.jpeg'].sort.reverse
Dir.mkdir("stamped") if !File.exist?("stamped")
numFork = 0
while !getImg.empty?
        numFork = numFork + 1
        photo = getImg.pop
        Process.fork{stampit(photo)}
        if numFork == NUMFORK
                Process.waitall
                numFork = 0
        end
end
Process.waitall
ส่วนแบบนี้คือการทำงานแบบต่อเนื่อง
NUMFORK = 2 
getImg = Dir['*.jpg','*.JPG','*.Jpg','*.jpeg'].sort.reverse
Dir.mkdir("stamped") if !File.exist?("stamped")
numFork = 0
while !getImg.empty?
        numFork = numFork + 1
        photo = getImg.pop
        Process.fork{stampit(photo)}
        if numFork >= NUMFORK
                Process.wait
                numFork = numFork - 1
        end
end
Process.waitall
อย่างนี้ก็สบายใช้งานคุ้มทุก core

Posted in ,  | Tags , , , ,  | no comments | no trackbacks

My Failure with Ruby Multi-Thread

Posted by Revolution Wed, 03 Sep 2008 16:57:00 GMT

คือว่าผมใช้ debian + ruby + rmagick เขียน script เพื่อที่จะทำการ stamp รูป แต่มาได้ความคิดว่า อย่าง convert เนี่ย ถ้าเราเรียก
$ convert -resize 1600 *.jpg
มันจะใช้ cpu 1 core เต็มๆ แต่อีก core จะชิวๆ หรือไม่ทำงานยุ่งเกี่ยวกับ convert เลย ก็เลยลองให้มันทำ
$ convert -resize 1600 *[02468].jpg &

$ convert -resize 1600 *[13579].jpg &
ผลลัพท์ที่ได้คือมันใช้ 2 core ทำงาน เป็นเพราะ shell เรียก convert นี่เป็น native ซึ่งมันจะไปทำงานแบบ fork จึงได้ผลลัพทธ์ดังกล่าว จากที่อ่านมา Fork คือ Heavy Weight Process ที่แยก resource กันชัดเจน ส่วน Thread คือ Light Weight Process ที่แบ่งปัน resource ซึ่งกันและกัน แต่ปัญหาอยู่ที่ว่าคือผมเขียน ruby คิดว่าถ้ามันเป็น thread ก็จะน่าได้ผลลัพธ์เช่นเดียวกับการ fork 2 ครั้ง แต่ผลลัพธ์ที่ได้กลับกลายเป็นว่า การทำงานนั้นไม่เต็ม 2 core คือใช้เพียงแค่ 1 core เท่านั้น จากการศึกษาเพิ่มเติมได้ผลออกมาว่า thread นั้นมี 2 แบบคือ user space และ kernel space
  • Kernel space จะเป็น thread แบบ native คือ kernel จะเป็นผู้จัดสรรและสับเปลี่ยน ก็จะได้ประสิทธิภาพตามคุณภาพของ kermel + cpu
  • User space หรือเรียกอีกอย่างว่า Green thread คือ thread ที่ทำงานแบบ time slice โดยผู้รับผิดชอบคือ VM (Virtual Machine) ในกรณีของผมคือ ruby นั่งเอง VM จะทำหน้าที่จัดสรรและสับเปลี่ยน เสหมือนเป็นการจำลอง thread อีกที ผลที่ได้คือ kernel เห็นเป็นเพีบง singel thread จึงทำงานได้เต็มที่แค่ 1 core
สรุปได้ว่า thread บน ruby นั้นป็น green thread จึงได้ผลลัพธ์ดังกล่าว ทางแก้ตอนนี้คือเขียนให้ ruby นั้น fork อีก process ไม่ใช่ว่า ruby thread จะไม่มีประโยชน์ ไว้จะลองเขียน ประโยชน์ของ ruby thread ดู

Posted in ,  | Tags , , , , , ,  | no comments | no trackbacks

Make a stamped for a Photo; ทำกรอบรอบรูป

Posted by Revolution Wed, 06 Aug 2008 10:03:00 GMT

หลังจากที่ได้ D80 มาสมใจอยาก เห็นหลายๆคนเวลาแสดงรูปจะมีการแสดงความเป็นเจ้าของโดยใส่ลายน้ำหรือใส่ข้อมูล exif หรือลายเซ็นไว้ ก็เลยอยากจะทำมั่ง ใน Photoshop ก็สามารถเขียน script(java script) ให้ทำทีละหลายๆรูปได้ หรือจะใช้ ACDSee ก็ทำได้ ส่วนสำหรับบน Linux ไม่ค่อยมีข้อมูลเท่าไหร่ แต่ Tools และ Libs เพียบ เลยตกงว่าจะออกกำลังเขียน ไหนๆก็ไหนๆ แล้วเขียนด้วย ruby ซะเลย นี่เป็น version ใช้เอง แต่ก็สามารถเขียนให้ดีกว่านี้เพื่อเอาไปใช้กับงานอื่นๆได้ code License GPL2


After I got D80, I saw many people show up their photos with a water mark, signature, exif data. I think that I have to do same way. Photoshop can do with a script, ACDSee can do also but Linux have no idea about that ( I may not know). By the way ,Linux come wiht many tools and Libs so I make a decision to write a ruby script for do that. This code is under GPL2 License. This version is for my own purpose, it may not be well design.


Requirement: Ruby 1.8.6, RMagick

Usage: run script at same Photo Directory, script will generate a directory "stamped" and file name is "stamped-.jpg" Read more...

Posted in ,  | Tags , ,  | no comments | no trackbacks

Passenger with some fcgi

Posted by Revolution Tue, 06 May 2008 15:37:00 GMT

I have a problem that I install passenger 1.0.3 that work fine with low transeaction web but for some web need high transaction , it need fcgi. The question that how can I use fcgi for some web and other run by passenger
<VirtualHost xxx>

RailsAllowModRewrite on
RailsAutoDetect off

</VirtualHost>

Posted in  | Tags , , , ,  | no comments | no trackbacks

Typo consumer too much memory

Posted by Revolution Tue, 29 Apr 2008 07:04:00 GMT

I monitor this application typo 5.0.2 consume too much memory about 50 – 80 MB which full feature. So i will try to make lite version for typo because I still like it. By the way, If my try is not successful, I will make my own blog system

มันกิน mem มากเหลือเกินไม่ไหว ถ้ามีโอกาศ จะลองทำแบบ lite ดู แต่ถ้าไม่ได้ลองเขียนใช้เองแล้ว ไม่ไหวเปลือง

Posted in  | Tags , ,  | no comments | no trackbacks

Speedthai Go to passenger 1.0.1

Posted by Revolution Fri, 18 Apr 2008 07:35:00 GMT

Now Speedthai Rails hosting in Thailand switch from Fcgid to Passenger (mod_rails) which consume less memory and better performance

ตอนนี้ Speedthai Rails Hosting ในประเทศไทยได้เปลี่ยนจาการใช้ fcgid ไปเป็น Passenger (mod_rails) ที่มีประสิทธิภาพดีกว่าและยังบริโภคแรมน้อยกว่า

อยู่ในขั้นทดสอบ

Posted in ,  | Tags , , , ,  | no comments | no trackbacks

Number to word in Thai

Posted by Revolution Wed, 20 Feb 2008 09:40:00 GMT

อยู่ในภาคทดสอบ แบ่งเป็น 2 แบบคืออ่านธรรมดากับแบบค่าเงิน

ทดสอบได้ที่ num2word

class Number

  def initialize
    @unit = %w[ศูนย์ หนึ่ง สอง สาม สี่ ห้า หก เจ็ด แปด เก้า]
    @qtys = ["แสน", "หมื่น", "พัน", "ร้อย", "สิบ", "หน่วย"]
    @mils = "ล้าน"
    @zero = "ศูนย์"
    @twenty = "ยี่"
    @unitone = "เอ็ด"
  end

  def self.th_word(number)
    Number.new.to_s(number)
  end

  def self.th_currency(number)
    Number.new.to_s_currency(number)
  end


  def self.commify(number)
    (s=number.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/(\d)(?=\d{3}+(\.\d*)?$)/, '\1,')
  end

  def to_s(value)
    if (number = value.to_s.split(".");number.length) >2 then return ("'.' more than 1") end
    re = []
    f = to_s_float(number[1]) if !number[1].nil?
    out = to_s_decimal(number[0])
    re[0] = f if !f.nil?
    re[1] = out
    if !f.nil? then re[2] = re[1] + "จุด" + re[0]   else re[2] = re[1] end
    return re.reverse
  end

  def to_s_currency(value)
    w = to_s(value).reverse
    f = value.to_s.gsub(/(\w*)+\./,"0.").to_f if !w[0].nil?
    w[0] = to_s_decimal((f * 100.0).round.to_s) if !f.nil?
    if !f.nil? then w[2] = w[1] + "จุด" + w[0]   else w[2] = w[1] end
    return w.reverse
  end

  def to_s_float(value)
    return float_wordify(value).flatten.compact.join(' ').gsub(/ ,/,',') 
  end

  def to_s_decimal(value)
    return quantify(value).flatten.compact.join(' ').gsub(/ ,/,',')
  end

private  

  def padded_groups(v)
    #make number to be 3 units per slot  by fill zero infront (x%3 =0)
    out = []
    padded = (s=v.to_s.gsub(/\D/i,"");x=s.length;s).rjust(x+(6-(x%6))).gsub(/ /,'0')
    padded.scan(/.{6}/)
  end

  def wordify(v)
    out = []
    @unitone = "หนึ่ง" if v.to_i == 1
    for cur in 0 .. v.length - 1
      if cur ==4 and v[cur] == '2'[0] 
        out << @twenty
      elsif cur ==4 and v[cur] == '1'[0] 
        out << "" 
      elsif cur ==5 and v[cur] == '1'[0] 
        out << @unitone
      else
      out << @unit[v[cur]-'0'[0]]
      end
    end
    return out
  end

  def float_wordify(v)
    out = []
    for cur in 0 .. v.length - 1
      out << @unit[v[cur]-'0'[0]]
    end
    out.pop while out.last == @zero
    return out
  end

  def quantify(v)
    v = padded_groups(v).reverse
    pos = v.length - 1
    out = []
    while pos >= 0
      if v[pos] == ','
        out << ','
        next
      end
      word = wordify(v[pos])
      for po in 0 .. word.length - 1
        if word[po] == @zero then next end
        if @qtys[po] != "หน่วย" then out << word[po] + @qtys[po] else out << word[po] end
      end
      out <<@mils if pos > 0
      pos -= 1
    end
    out.shift while out.first == @mils
    out << @zero if out.length.zero?
    return out
  end

end

Posted in  | Tags , , ,  | no comments | no trackbacks

Number to word

Posted by Revolution Tue, 12 Feb 2008 10:35:00 GMT

Source จาก http://sohne.net/articles/2006/04/30/convert-numbers-to-words/ เท่าที่แกะดูก็ไม่ยากแต่ไม่เข้าใจว่า หลายที่เงื่อนไขไม่ลงเลย สงสัยทำเผื่อไว้

Source from http://sohne.net/articles/2006/04/30/convert-numbers-to-words/ I have some confuse with this code, some condition will not may happen but i still be.

มีที่ดีกว่านี้ที่ http://www.deveiate.org/projects/Linguistics/wiki/English

class Number

  def self.to_words(number)
    Number.new.to_s(number)
  end

  def self.commify(number)
    (s=number.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/(\d)(?=\d{3}+(\.\d*)?$)/, '\1,')
  end

  def initialize
    @unit = %w[zero one two three four five six seven eight nine]
    @teen = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen]
    @tens = %w[zero ten twenty thirty fourty fifty sixty seventy eighty ninety]
    @qtys = %w[hundred thousand million billion trillion quadrillion quintillion]
    @zero = ["zero"]
    @hundred = "hundred"
    @sepr = "and"
  end

  def to_s(number)
    out = quantify(number).flatten
    for x in 0 .. out.length - 1
      out[x] = nil if out[x] == @sepr && out[x+1] == @sepr
      out[x] = nil if out[x] == "," && out[x+1] == ","      
    end
    out.compact!
    out = @zero if out.length == 1 && out[0] == @sepr
    out.pop while out.last == @sepr
    out.shift while out.first == @sepr    
    out.join(' ').gsub(/ ,/,',')
  end

  private 

  def padded_groups(v)
    #make number to be 3 units per slot  by fill zero infront (x%3 =0)
    out = []
    padded = (s=v.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/ /,'0')
    padded.scan(/.{3}/)
  end

  def wordify(v)
    #Get 3 unit of slot and compare by ascii code, then word it out
    out = []
    zero = '0'[0]
    h, t, u = v[0] - zero, v[1] - zero, v[2] - zero
    if h != 0
      out << @unit[h]
      out << @hundred
    end
    #"and" word will add when hundred appear and unit appear 
    out << @sepr if h != 0 && (t != 0 || u != 0)
    out << @sepr if h == 0 && t == 0 && u != 0
    if t == 1
      out << @teen[u]
    else
      out << @tens[t] if t != 0
      out << @unit[u] if u != 0
    end
    return out
  end

  def quantify(v)
    #make ach 3 of each slot to be a word by calling wodify
    v = padded_groups(v).reverse
    cur = pos = v.length - 1
    out = []
    while pos >= 0
      if v[pos] == ','
        out << ','
        next
      end
      word = wordify(v[pos])
      if word[0] != nil
        out << word
        out << @qtys[cur] if cur != 0                
      else
        out << @sepr
      end
      cur -= 1
      pos -= 1
    end
    return out
  end

end

puts Number.to_words(1234567890)
puts Number.commify(1234567890)

ถ้าอยากรู้ว่า code ทำงานอย่างไรอ่านต่อข้างใน

Read more...

Posted in  | Tags  | 1 comment | no trackbacks

Ruby.NET เลิกพัฒนา

Posted by Revolution Tue, 05 Feb 2008 12:20:00 GMT

เขียนลง Blognone

Ruby เป็นภาษาที่ได้รับความสนใจไม่น้อย จนกระทั่งมีคนอยากให้ใช้งานกับ .NET ได้ด้วย ทางด๊อกเตอร์เคลลี่ ผู้พัฒนา Ruby.NET ได้ประกาศผ่านทางกูเกิ้ลกรุ๊ปแล้วว่าเขาจะเลิกพัฒนา Ruby.NET โดยเหตุผลว่า IronRuby นั่นประสพความสำเร็จและไปได้ไกลกว่า

เนื่องจาก Ruby.NET เองแรกเริ่มก็เป็นโครงงานที่แตกตัวออกมาจาก IronRuby ซึ่งถ้าจะทำ Ruby.NET ให้เข้าได้กับ DLR (Dynamic Language Runtime) ต้องทำการเปลี่ยนแปลงหลายอย่าง และด๊อกเตอร์เคลลี่มั่นใจว่ามันจะดีกว่า CLR (Common Language Runtime) ที่ใช้อยู่ในปัจจุบัน

ทางผู้พัฒนา Ruby.NET ก็มีทีท่าจะไปช่วยพัฒนา IronRuby อยู่ด้วย

ที่มา: Google Group

Posted in  | Tags ,  | no comments | no trackbacks

Older posts: 1 2 3