2010-12-13 64 views
9

Tôi muốn nhận được màu phổ biến nhất từ ​​một hình ảnh. Tôi sử dụng Java và tôi muốn có màu chủ đạo nhất. Có thư viện java cbir nào để làm điều này không?Lấy màu phổ biến nhất của hình ảnh

Cảm ơn

+0

Chính xác những gì bạn có ý nghĩa bởi "chủ yếu"? – Thomas

+0

Màu phổ biến nhất trong hình ảnh? –

Trả lời

2

Bạn có thể lặp các BufferedImage (hai vòng - một từ 0 đến chiều rộng, và một từ 0 đến chiều cao), và nhận được cuộc gọi getRgb(x, y). Sau đó đếm từng giá trị khác nhau. Bạn có thể sử dụng Map cho điều đó (khóa = màu, giá trị = số lần xuất hiện).

+0

Thật sao? Có thể có tới 16,581,375 màu. – dogbane

+0

Vì vậy, bạn lo lắng về bộ nhớ? – Bozho

+2

Có. Có thể chỉ là PC của tôi, nhưng tôi có một OOM sau khoảng 4 triệu màu trong bản đồ của tôi. – dogbane

9

Bạn muốn điều này chính xác đến mức nào? Bạn có thể sử dụng phương pháp tiếp cận của Bozhos và lặp lại toàn bộ hình ảnh nhưng điều này có thể chậm đối với hình ảnh lớn. Có 16777216 giá trị RGB có thể và giữ cho quầy cho chúng trong một Bản đồ không phải là rất hiệu quả.

Cách khác là lấy lại mẫu hình ảnh bằng cách sử dụng getScaledInstance để chia tỷ lệ hình ảnh thành phiên bản nhỏ hơn, ví dụ: hình ảnh 1x1 và sau đó sử dụng getRGB để lấy màu của pixel đó. Bạn có thể thử nghiệm với các thuật toán lấy lại mẫu khác nhau chẳng hạn như SCALE_REPLICATESCALE_AREA_AVERAGING để xem những gì phù hợp nhất với bạn.

+0

Lưu ý rằng cách tiếp cận này sẽ cho kết quả khác với cách tiếp cận của Bozhos. Trong phần sau, màu xuất hiện thường xuyên nhất trong ảnh được xác định trong khi cách tiếp cận của bạn cố gắng tìm một thứ như "màu trung bình" - một khái niệm không rõ ràng, nhưng rõ ràng là màu được trả về có thể không xuất hiện ở bất kỳ đâu trong bản gốc hình ảnh.Tôi không nói một cách tiếp cận nào tốt hơn phương pháp khác, tôi đoán áp phích ban đầu phải làm rõ những gì anh ta đang tìm kiếm. – Thomas

+0

Vâng, tôi hiểu rằng, vì vậy tại sao tôi hỏi độ chính xác là bao nhiêu. Nếu bạn sử dụng 'ReplicateScaleFilter', bạn sẽ nhận được một màu xuất hiện trong ảnh gốc vì nó" bỏ qua các hàng và các cột của các điểm ảnh để co giãn ". Nó không làm bất kỳ "trộn" nào giống như 'AreaAveragingScaleFilter'. – dogbane

+1

Bạn lấy số 16581375 ở đâu? Nếu chúng ta đang nói về 8 bit cho mỗi kênh, có 2^24 = 16777216 giá trị RGB có thể. – Jesper

3

Điều gì sẽ xảy ra nếu bạn xem hình ảnh của mình là một mảng tuyến tính lớn pixel và sau đó tất cả những gì bạn phải làm chỉ là sắp xếp nó? Khi bạn đã sắp xếp nó, bạn có thể đếm phần dài nhất của cùng một giá trị.

3

Tùy thuộc vào mức độ chính xác mà bạn cần giá trị màu, bạn có thể muốn xem xét "nhóm màu" thu thập các màu tương tự để tránh các vấn đề về bộ nhớ. Điều này có nghĩa là phân vùng không gian màu thành "khoảng thời gian" của màu sắc, trong đó tất cả các màu tương tự (tức là gần nhau) đủ đều được tính là cùng một màu. Bằng cách thay đổi kích thước khoảng thời gian bạn có một phương tiện trực tiếp thao tác thương mại-off giữa độ chính xác và tiêu thụ bộ nhớ.


Chỉnh sửa: Nội dung bạn muốn về cơ bản là biểu đồ (hãy tra cứu). Có lẽ hầu hết các giải pháp tiêu chuẩn được thiết lập tốt để tính toán hiệu quả một trong số đó.

+0

Có, chỉ cần đếm từng màu (khá dễ sử dụng giá trị màu làm chỉ mục cho một mảng các số nguyên) mà bạn có thể tăng nhanh chóng. Mảng sẽ nhỏ hơn hình ảnh đang được phân tích và tăng số nguyên là khá rẻ trong hầu hết các ngôn ngữ lập trình (tất cả?). – Eno

1

Tôi sẽ tính toán màu sắc của mỗi pixel và sau đó tính số của mỗi màu (tạo biểu đồ). Có lẽ trọng lượng bởi bão hòa. Sau đó, áp dụng bộ lọc low-pass và tìm mức tối đa. Cuối cùng chuyển đổi từ màu sắc trở lại RGB.

Giả định rằng nếu bạn chỉ có mặt phẳng màu đỏ của hình ảnh, bạn muốn kết quả là "màu đỏ", không phải một chút màu hồng.

4

Cảm ơn câu trả lời. Đây là một ví dụ thực tế về phương pháp của Bozho. Nó cũng lọc ra trắng/xám/đen.

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Map; 
import javax.imageio.ImageIO; 
import javax.imageio.ImageReader; 
import javax.imageio.stream.ImageInputStream; 


public class ImageTester { 


    public static void main(String args[]) throws Exception { 
     File file = new File("C:\\Users\\Andrew\\Desktop\\myImage.gif"); 
     ImageInputStream is = ImageIO.createImageInputStream(file); 
     Iterator iter = ImageIO.getImageReaders(is); 

     if (!iter.hasNext()) 
     { 
      System.out.println("Cannot load the specified file "+ file); 
      System.exit(1); 
     } 
     ImageReader imageReader = (ImageReader)iter.next(); 
     imageReader.setInput(is); 

     BufferedImage image = imageReader.read(0); 

     int height = image.getHeight(); 
     int width = image.getWidth(); 

     Map m = new HashMap(); 
     for(int i=0; i < width ; i++) 
     { 
      for(int j=0; j < height ; j++) 
      { 
       int rgb = image.getRGB(i, j); 
       int[] rgbArr = getRGBArr(rgb);     
       // Filter out grays....     
       if (!isGray(rgbArr)) {     
         Integer counter = (Integer) m.get(rgb); 
         if (counter == null) 
          counter = 0; 
         counter++;         
         m.put(rgb, counter);     
       }     
      } 
     }   
     String colourHex = getMostCommonColour(m); 
     System.out.println(colourHex); 
    } 


    public static String getMostCommonColour(Map map) { 
     List list = new LinkedList(map.entrySet()); 
     Collections.sort(list, new Comparator() { 
       public int compare(Object o1, Object o2) { 
       return ((Comparable) ((Map.Entry) (o1)).getValue()) 
        .compareTo(((Map.Entry) (o2)).getValue()); 
       } 
     });  
     Map.Entry me = (Map.Entry)list.get(list.size()-1); 
     int[] rgb= getRGBArr((Integer)me.getKey()); 
     return Integer.toHexString(rgb[0])+" "+Integer.toHexString(rgb[1])+" "+Integer.toHexString(rgb[2]);   
    }  

    public static int[] getRGBArr(int pixel) { 
     int alpha = (pixel >> 24) & 0xff; 
     int red = (pixel >> 16) & 0xff; 
     int green = (pixel >> 8) & 0xff; 
     int blue = (pixel) & 0xff; 
     return new int[]{red,green,blue}; 

    } 
    public static boolean isGray(int[] rgbArr) { 
     int rgDiff = rgbArr[0] - rgbArr[1]; 
     int rbDiff = rgbArr[0] - rgbArr[2]; 
     // Filter out black, white and grays...... (tolerance within 10 pixels) 
     int tolerance = 10; 
     if (rgDiff > tolerance || rgDiff < -tolerance) 
      if (rbDiff > tolerance || rbDiff < -tolerance) { 
       return false; 
      }     
     return true; 
    } 
} 
+0

trông giống như một cách làm đắt tiền bằng cách lặp qua từng pixel. Nó sẽ dễ dàng chết vì ảnh 5MP – Taranfx

+0

Nếu hình ảnh lớn, hãy thay đổi kích thước trước. –

0

Andrew Dyster đang làm việc tốt, phản ứng nhanh trong android

import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Map; 

import android.graphics.Bitmap; 

public class ImageTester { 

    public interface ImageColor { 
     void onImageColor(int r, int g, int b); 
    } 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    public static void getMostCommonColour(final Bitmap image, 
      final ImageColor heColor) { 
     new Thread(new Runnable() { 
      private int rgb; 

      @Override 
      public void run() { 
       int height = image.getHeight(); 
       int width = image.getWidth(); 
       Map m = new HashMap(); 
       int boderWid = width/4; 
       int borderHeigh = height/4; 

       for (int i = boderWid; i < width - boderWid;) { 
        for (int j = borderHeigh; j < height - borderHeigh;) { 
         try { 
          rgb = image.getPixel(i, j); 

         } catch (Exception e) { 
          continue; 
         }finally{ 
          i += 20; 
          j += 20; 
         } 
         int[] rgbArr = getRGBArr(rgb); 
         // Filter out grays.... 
         if (!isGray(rgbArr)) { 
          Integer counter = (Integer) m.get(rgb); 
          if (counter == null) 
           counter = 0; 
          counter++; 
          m.put(rgb, counter); 

         } 

        } 
       } 
       List list = new LinkedList(m.entrySet()); 
       Collections.sort(list, new Comparator() { 
        public int compare(Object o1, Object o2) { 
         return ((Comparable) ((Map.Entry) (o1)).getValue()) 
           .compareTo(((Map.Entry) (o2)).getValue()); 
        } 
       }); 
       Map.Entry me = (Map.Entry) list.get(list.size() - 1); 
       int[] rgb = getRGBArr((Integer) me.getKey()); 
       heColor.onImageColor(rgb[0], rgb[1], rgb[2]); 

      } 
     }).start(); 
    } 

    public static int[] getRGBArr(int pixel) { 
     int red = (pixel >> 16) & 0xff; 
     int green = (pixel >> 8) & 0xff; 
     int blue = (pixel) & 0xff; 
     return new int[] { red, green, blue }; 

    } 

    public static boolean isGray(int[] rgbArr) { 
     int rgDiff = rgbArr[0] - rgbArr[1]; 
     int rbDiff = rgbArr[0] - rgbArr[2]; 
     int tolerance = 10; 
     if (rgDiff > tolerance || rgDiff < -tolerance) 
      if (rbDiff > tolerance || rbDiff < -tolerance) { 
       return false; 
      } 
     return true; 
    } 
} 
Các vấn đề liên quan