Building a Color-based Image Search Engine in Ruby
Source: http://www.toptal.com/ruby/building-color-based-image-search-engine-ruby Người ta nói rằng một bức tranh trị giá hơn cả ngàn chữ. Và trong nhiều trường hợp thì các từ trong hình ảnh là màu sắc. Màu sắc là một phần không thể thiếu trong cuộc sống của chúng ta, và chúng ta không thể phủ ...
Source: http://www.toptal.com/ruby/building-color-based-image-search-engine-ruby
Người ta nói rằng một bức tranh trị giá hơn cả ngàn chữ. Và trong nhiều trường hợp thì các từ trong hình ảnh là màu sắc. Màu sắc là một phần không thể thiếu trong cuộc sống của chúng ta, và chúng ta không thể phủ nhận tầm quan trọng của chúng.
Khi nhìn vào một bức ảnh, chúng ta thường cố gắng để xác định màu sắc trên từng phần, từng khu vực của nó. Chúng tôi đã cố gắng làm tất cả điều đó nhưng không bao giờ làm nó một cách chi tiết. Khi được hỏi để xác định màu sắc từ một hình ảnh, chúng ta có xu hướng đánh giá chúng bằng cách sử dụng tên màu sắc cụ thể, chẳng hạn như màu đỏ, xanh dương và xanh lá cây. Tuy nhiên, nếu được hỏi tìm ra 30 màu nổi bật nhất trong một hình ảnh thì mắt của chúng ta không thể phát hiện hoặc nhận ra chúng dễ dàng được. Camalian được tạo ra để giải quyết việc này. Nó giúp bạn phân tích các màu sắc từ một hình ảnh và sau đó xử lý chúng.
Trong bài viết này, chúng ta sẽ hòa mình vào không gian màu sắc, cùng những gì Ruby Camalian cung cấp, và làm thế nào có thể sử dụng để tạo ra một công cụ tìm kiếm hình ảnh đơn giản sử dụng màu sắc để xác định và phân biệt chúng.
I, Colors Space
Trước khi bắt đầu, chúng ta hãy đi tìm hiểu một số khái niệm cơ bản về màu sắc. Hình ảnh thể hiện trên màn hình của chúng ta được cấu thành bằng cách sử dụng một mảng hai chiều của các điểm ảnh pixel. Mặc dù các tập tin hình ảnh có thể được mã hóa theo những cách khác nhau, nhưng cơ bản khi giải nén và giải mã dữ liệu là như nhau. Trong không gian 2d, mỗi điểm ảnh trong một hình ảnh được cấu tạo bởi ba thành phần: đỏ, xanh lá cây và màu xanh hay còn gọi tắt là RGB. Hình ảnh in trên giấy cũng là một mặt phẳng hai chiều của các điểm, mỗi điểm chính là một hỗn hợp của bốn loại mực thành phần: lục lam, đỏ tươi, màu vàng và màu đen. Những kỹ thuật khác nhau được sử dụng để xây dựng nên màu sắc được gọi là không gian màu. Một số không gian màu sắc phổ biến nhất được sử dụng là RGB, CMYK, HSL và HSV. CMYK là chủ yếu được sử dụng trong các ngành công nghiệp in ấn trong khi tất cả những loại khác được sử dụng trong các phương tiện truyền thông kỹ thuật số.
II, RGB Color Space
Bất kỳ phương tiện truyền thông điện tử vật lý nào như màn hình CRT, màn hình LCD, hay điện thoại sắc đều hiển thị màu sắc bằng cách sử dụng ba thành phần: đỏ, xanh lá cây, xanh dương. Mắt người có thể phát hiện hàng triệu màu bằng cách tổng hợp ba loại màu sắc R G B này trong mắt.
Do đó, mỗi thành phần màu được lưu trữ trong một byte có giá trị có thể nằm trong khoảng từ 0 đến 255.
III, HSL & HSV Color Space
Bố trí không gian màu RGB trên một khối lập phương là khá thách thức. Các kết quả cố gắng để thể hiện nó trên một khối lập phương khá nghèo nàn. Trong khi làm việc với hàng triệu màu sắc, mỗi sắc thái của màu sắc có thể không được liên kết đúng vào không gian màu RGB.
Để khắc phục vấn đề này, trong năm 1970 các nhà nghiên cứu giới thiệu HSV (Hue, Saturation, Value) và HSL (Hue, Saturation, Lightness) không gian màu. Cả hai không gian màu sắc có thể được xếp trên một bánh xe màu sắc đúng cách và làm cho nó dễ dàng hơn để xác định sắc thái màu khác nhau của màu sắc trên đó.
IV, Ruby Gem for Colors
Camalian là tất cả về màu sắc. Một trong những điều đơn giản nhất bạn có thể làm với Camalian là xác định từng sắc thái của các màu sắc được sử dụng trong một hình ảnh.
Hãy cùng xem một hình ảnh với 15 màu sắc khác nhau:
Xác định các màu sắc từ swatch trên chắc chắn dễ dàng hơn nhiều so với xác định chúng từ các hình ảnh gốc. Hơn nữa, đây chỉ là một hình ảnh đơn giản, trong thực tế ta có thể bắt gặp các hình ảnh đa dạng màu sắc hơn rất nhiều. Trích xuất các giá trị màu sắc từ hình ảnh đòi hỏi một số bit khá phức tạp, Camalian sẽ giúp bạn. Nó giúp bạn có thể trích xuất màu sắc liên quan đến thông tin từ một hình ảnh một cách dễ dàng.
V, Getting Started
Nếu như việc phân tích màu sắc với Camalian là dễ dàng, thì việc cài đặt với nó thậm chí còn dễ dàng hơn. Bạn có thể cài đặt các gem Ruby bằng cách thực hiện:
gem install camalian
Để sử dụng gem này:
require 'camalian'
VI, Extracting Colors
Để giải nén các màu sắc từ một hình ảnh, đầu tiên chúng ta cần phải load nó vào trong bộ nhớ, và sử dụng các phương pháp trên các đối tượng hình ảnh
image = Camalian::load( File.join( File.dirname(__FILE__), 'colormap.png') ) colors = image.prominent_colors(15) puts colors.map(&:to_hex)
Đoạn mã này tải một hình ảnh có tên "colormap.png" từ thư mục lưu trữ và trích xuất ra 15 màu sắc nổi bật nhất từ nó.
Để chạy nó, lưu tập tin với tên "color_test1.rb" và chạy nó trong shell bằng lệnh:
ruby color_test1.rb.
Kết quả được hiển thị như sau:
["#318578", "#41b53f", "#2560a3", "#359169", "#2154b1", "#4dda15", "#1d48bf", "#1530dc", "#296d94", "#193dcd", "#3da94d", "#45c131", "#3da84e", "#2d7986", "#193cce"]
Và nó thật dễ dàng! Chúng ta đã chỉ trích 15 màu sắc được sử dụng trong hình trên. Lần này, chúng ta sẽ cố gắng sử dụng Camalian trên một hình ảnh với các cụ thể như sau:
Sau khi chạy đoạn mã trên ta thu được kết quả:
[“#210b03”, “#723209”, “#974d09”, “#ae5d08”, “#c77414”, “#d77f15”, “#ffea54”, “#94651f”, “#b66a15”, “#c25f06”, “#fdd94d”, “#d39a39”, “#efa540”, “#fffffe”, “#fff655”]
Hãy thử hình dung mảng các màu sắc trên được hiển thị như sau:
Các bảng màu rất có ích, nhưng không có mẫu đặc trưng cho việc hiển thị các màu sắc chiết xuất. Hãy sắp xếp các giá trị màu bằng sự giống nhau và xem chúng. Tất cả chúng ta cần phải làm là gọi thêm một chức năng trước khi thực sự in mảng:
colors = image.prominent_colors(15).sort_similar_colors
Nhưng nếu chúng ta muốn giải nén màu sắc mà nhẹ hơn? Có thể là chúng ta muốn màu sắc mà chỉ có 40% tối, hay nói cách khác có một nhẹ nhàng (trong không gian màu HSL) giá trị giữa 0 và 40. Tất cả chúng ta cần phải làm là:
colors = image.prominent_colors(15).light_colors(0, 40)
VII, Making the Image Search Engine
Bây giờ chúng ta biết cách dễ dàng là để xử lý với các màu sắc sử dụng Camalian, hãy xây dựng một ứng dụng web đơn giản cho phép bạn tải lên hình ảnh và chúng được index bởi các màu sắc. Cho ngắn gọn, chúng ta sẽ bỏ qua các chi tiết khác nhau có liên quan trong việc xây dựng một ứng dụng Ruby. Thay vào đó, chúng ta sẽ tập trung vào chi tiết cụ thể xử lý với màu sắc và cách sử dụng Camalian.
Trong ứng dụng, chúng ta sẽ xử lý tải ảnh lên, giải nén màu sắc từ chúng trước khi lưu trữ, và tìm kiếm các hình ảnh được tải lên dựa trên màu sắc được lựa chọn. Model diagram giải thích cấu trúc ứng dụng này:
Mỗi hình ảnh được tải lên được đại diện bằng một đối tượng PortfolioItem. Mỗi đối tượng Color đại diện cho màu sắc độc đáo được phát hiện thông qua các hình ảnh được tải lên, và cuối cùng PortfolioColor đại diện cho mối quan hệ giữa mỗi hình ảnh và màu sắc được tìm thấy trong nó.
Hầu hết các bit của ứng dụng là khá chuẩn, đặc biệt là khi nói đến xử lý tải ảnh lên, tạo ra các thực thể mẫu và lưu trữ đến cơ sở dữ liệu, vv. Dưới đây là phương pháp được sử dụng để trích xuất các màu sắc từ hình ảnh tải lên:
after_save :extract_colors private def extract_colors image = Camalian::load(self.image.path) colors = image.prominent_colors(self.color_count.to_i).sort_similar_colors colors.each do |color| unless c = Color.where(r: color.r, g: color.g, b: color.b).first c = Color.create(r: color.r, g: color.g, b: color.b, h: color.h, s: color.s, l: color.l) end self.colors << c end end
Điều này giúp chiết xuất các bảng màu và lưu trữ vào cơ sở dữ liệu. Chú ý rằng chúng chỉ trích xuất một số màu sắc nổi bật (một cái gì đó mà người dùng có thể xác định khi tải lên các hình ảnh).
Khi một người dùng gửi một hình ảnh thông qua các hình thức trên giao diện web, hình ảnh được nhận thông qua một trình xử lý, và một PortfolioItem mới được tạo ra cho nó. Phương pháp này, extract_colors, được gọi bất cứ khi nào một đối tượng được save
Để render một bảng màu, chúng ta sử dụng một helper:
module PortfolioItemsHelper def print_color_palette(colors) color_string = ' colors.each do |c| color_string += content_tag :span, ' ', style: "display: block; float: left; awidth: 35px; height: 35px; background: #{c.to_hex}" end content_tag :div, color_string.html_safe, style: "display: inline-block;" end end
Và cuối cùng, để thực thi search chúng ta phải sử dụng một số thuật toán logic:
class PortfolioSearchForm include ActiveModel::Model attr_accessor :color, :similarity validates_presence_of :color, :similarity def color_object @color_object ||= Camalian::Color.new(self.color) end def color_range(color, level) (color_object.send(color) - level)..(color_object.send(color) + level) end def colors_by_rgb level = self.similarity.to_i * 255 / 100.0 Color.where(r: color_range(:r, level), g: color_range(:g, level), b: color_range(:b, level)) end def colors_by_hsl level = self.similarity.to_i Color.where(h: color_range(:h, (self.similarity.to_i * 30 / 100.0) ), s: color_range(:s, level), l: color_range(:l, level)) end end
Demo:
https://imagesearchengine.herokuapp.com/