2009-03-07 47 views
8

Đối với một dự án sở thích, tôi sẽ xây dựng một chương trình khi đưa ra một bitmap hình ảnh sẽ tạo ra một mẫu cross-stitch dưới dạng PDF. Tôi sẽ sử dụng Cocoa/Objective C trên máy Mac.Làm cách nào để giảm bitmap thành bộ màu RGB đã biết

Bitmap nguồn thường sẽ là hình ảnh 24bpp, nhưng trong số hàng triệu màu có sẵn, chỉ có một số ít tồn tại dưới dạng các chuỗi cross-stitch. Chủ đề có nhiều loại khác nhau. DMC là phổ biến nhất, và gần như toàn bộ phạm vi của họ có sẵn như là giá trị RGB từ các trang web khác nhau. Ví dụ: Here's one.

DMC# Name    R G B 
----- ------------------ --- --- --- 
blanc White    255 255 255 
208 Lavender - vy dk 148 91 128 
209 Lavender - dk  206 148 186 
210 Lavender - md  236 207 225 
211 Lavender - lt  243 218 228 
     ...etc... 

Vấn đề đầu tiên, như tôi thấy, là từ điểm bắt đầu của RGB từ điểm ảnh trong hình chọn màu gần nhất có sẵn từ bộ DMC. Cách tốt nhất để tìm ra màu DMC gần nhất về mặt toán học là gì, và đảm bảo rằng nó gần như phù hợp với màu sắc?

Mặc dù tôi sẽ sử dụng Cocoa, vui lòng sử dụng mã giả (hoặc thậm chí Java!) Trong bất kỳ mã nào bạn đăng.

+0

Đợi? http://stackoverflow.com/questions/492211/is-there-an-easy-way-to-compare-how-close-two-colors-are-to-each-other – bzlm

+0

Bạn có thể sử dụng imagemagick cho điều này, http : //www.imagemagick.org/Usage/quantize/ –

+0

nếu các mũi khâu chéo của bạn không cần phải căn chỉnh thì [dithering] (http://stackoverflow.com/a/36820654/2521214) là bạn của bạn (như bạn có bảng màu cố định).Quantization thường hạn chế số lượng màu sắc từ những gì hình ảnh đầu vào bao gồm nhưng bảng màu của bạn có thể có màu sắc không có trong hình ảnh ở tất cả dẫn đến biến dạng màu sắc kỳ lạ. Để phối màu phù hợp, bạn cần ít nhất: Đỏ, Xanh lục, Xanh lam, Lục lam, Đỏ tươi, Vàng, Đen, Trắng. Nếu bạn có nhiều thì một cường độ tốt hơn nhưng nó cũng hoạt động với cường độ đơn trên mỗi màu. – Spektre

Trả lời

10

Sử dụng không gian màu LAB và tìm màu bằng euclidean distance gần nhất. Làm điều này trong không gian màu RGB sẽ mang lại kết quả phản trực giác. (Hoặc sử dụng không gian màu HSL.)

Vì vậy, chỉ cần lặp qua từng pixel và tìm màu với khoảng cách gần nhất trong không gian màu bạn chọn. Lưu ý rằng khoảng cách phải được tính theo chiều ngang đối với một số không gian màu (ví dụ: các không gian màu đó sử dụng màu sắc).

(Hầu hết quanization màu xoay quanh thực sự lựa chọn một bảng màu, nhưng điều đó đã được đưa về chăm sóc trong trường hợp của bạn, vì vậy bạn không thể sử dụng các kỹ thuật lượng tử phổ biến hơn.)

Ngoài ra, hãy kiểm tra this question.

Để tìm mã HSB trong Ca cao, có vẻ như bạn có thể sử dụng getHue method declared in NSColor.h.

Tuy nhiên, nếu bạn chỉ chuyển đổi hình ảnh thành thiết kế chéo bằng cách sử dụng kỹ thuật này, sẽ rất khó để thực sự khâu nó. Nó sẽ có đầy đủ các trường màu đơn pixel, mà loại đánh bại mục đích của cross-stitching.

+0

Bạn giả định hình ảnh nguồn là một bức ảnh, nhưng có. Có một loạt các công cụ cross-stitch tôi đã xem xét, nhưng không muốn quá tải câu hỏi. – banjollity

+0

Không, tôi thực sự không giả định điều đó. Tôi chỉ nói về cách tiếp cận "mỗi pixel" không xem xét toàn bộ hình ảnh. Nhưng nếu hình ảnh nguồn của bạn đã được lượng hóa rất nhiều, thì đó là nguồn gốc không có vấn đề gì. (Tôi đã chia sẻ của tôi về khâu bitching thumb-soring bitching.) – bzlm

+0

Tôi không nghĩ rằng chi tiết về ý định của bạn sẽ quá tải câu hỏi. – bzlm

3

Điều này được gọi là color quantization và có nhiều thuật toán khả dụng.

Một điều rất cơ bản là chỉ xử lý màu RGB như các điểm trong không gian và sử dụng khoảng cách Euclidian cũ đồng bằng giữa các màu để tìm ra cách "đóng" chúng. Điều này có nhược điểm, vì mắt người có độ nhạy khác nhau ở những nơi khác nhau trong không gian này, do đó khoảng cách như vậy sẽ không tương ứng tốt với cách con người cảm nhận màu sắc. Bạn có thể sử dụng các lược đồ trọng số khác nhau để cải thiện tình huống đó.

+0

Thay vì các chương trình cân nặng pha chế tại nhà, tôi đề xuất một không gian màu thay thế. – bzlm

1

lấy nguồn cho các ứng dụng ppmquant từ tập netpbm của tiện ích

-1

Tùy thuộc vào sự liên quan của tính chính xác của các hoạt động màu sắc của bạn, hãy nhớ mang color space s vào tài khoản. Trong khi tôi đã nghiên cứu điều này một chút, do sở thích nhiếp ảnh của tôi, tôi vẫn còn chút bối rối về mọi thứ.Tuy nhiên, như đã đề cập, sử dụng LAB càng nhiều càng tốt, bởi vì (afaik) không gian màu bất khả tri, trong khi tất cả các phương pháp khác (RGB/HSL/CMYK) có nghĩa là không có gì (theo lý thuyết) mà không có không gian màu được xác định. Ví dụ:

RGB chỉ là ba giá trị phần trăm (0-255 => 0-100%, với độ sâu màu 8 bit). Vì vậy, nếu bạn có một bộ ba RGB (0,255,0), nó dịch thành "chỉ màu xanh lá cây, và càng nhiều càng tốt". Vì vậy, câu hỏi đặt ra là "đỏ như thế nào?". Đây là câu hỏi mà một không gian màu trả lời - sRGB 100%-xanh không phải là màu xanh lá cây như AdobeRGB 100%-xanh. Nó thậm chí không giống nhau hue!

Xin lỗi nếu điều này đã đi đến bên Offtopic thứ

+0

Tôi đồng ý, suy nghĩ về màu sắc (sử dụng LAB hoặc HSx) là điều quan trọng ở đây. – bzlm

+0

Wikipedia: "Ngoài ra, nhiều" màu sắc "trong không gian Lab nằm ngoài tầm nhìn của con người, và do đó hoàn toàn là tưởng tượng; những 'màu' này không thể được tái tạo trong thế giới vật chất." - LAB vừa phá vỡ đầu tôi! – banjollity

+0

Vâng, tại sao giới hạn bản thân với thế giới vật lý? Tất cả các bạn chỉ trong đầu tôi. – bzlm

1

Những người khác đã chỉ ra các kỹ thuật khác nhau cho lượng tử màu. Có thể sử dụng các kỹ thuật như Markov Random Fields để cố gắng phạt hệ thống để chuyển đổi màu chủ đề tại các vị trí pixel lân cận. Có một số thư viện MRF nhiều nhãn chung nằm ngoài đó bao gồm Boykov's.

Để sử dụng một trong các yếu tố dữ liệu sẽ là màu đầu vào, nhãn sẽ là tập hợp các màu của chuỗi, các thuật ngữ dữ liệu có thể giống như khoảng cách Euclide trong không gian LAB được đề xuất bởi bzlm và các cụm từ lân cận sẽ phạt cho việc chuyển đổi màu chủ đề.

+1

Ai nghĩ rằng stiching yêu cầu một mức độ trong khoa học máy tính? – bzlm

+0

Có lẽ một mức độ khoa học máy tính nên yêu cầu một số khâu? – banjollity

2

Interresting ... :)

Bạn sẽ không chỉ xác định màu gần nhất, bạn cũng sẽ muốn giảm số lượng màu được sử dụng. Bạn không muốn kết thúc bằng một mẫu ghép có sử dụng hàng trăm màu khác nhau ...

Tôi đã đặt cùng một số mã thực hiện điều này ở cấp cơ bản. (Xin lỗi vì nó ở trong C#, tôi hy vọng rằng nó có thể có ích một chút.)

Có một số tinh chỉnh cần thực hiện trước khi phương thức hoạt động tốt, tất nhiên. Phương pháp GetDistance cân nhắc tầm quan trọng của màu sắc, độ bão hòa và độ sáng với nhau, việc tìm ra sự cân bằng tốt nhất giữa những thứ đó tất nhiên là quan trọng để tìm màu gần nhất.

Ngoài ra còn có nhiều việc có thể thực hiện bằng phương pháp giảm bảng màu. Trong ví dụ này, tôi chỉ chọn các màu được sử dụng nhiều nhất, nhưng bạn có thể muốn cân bằng màu sắc trong bảng màu. Điều này có thể được thực hiện bằng cách chọn màu được sử dụng nhiều nhất, giảm số lượng cho các màu còn lại trong danh sách tùy thuộc vào khoảng cách đến màu đã chọn và sau đó sử dụng danh sách.

Lớp HSL chứa một màu DMC, có thể tính toán khoảng cách đến màu khác, và tìm ra màu gần nhất trong một danh sách các màu sắc:

public class Hsl { 

    public string DmcNumber { get; private set; } 
    public Color Color { get; private set; } 
    public float Hue { get; private set; } 
    public float Saturation { get; private set; } 
    public float Brightness { get; private set; } 
    public int Count { get; set; } 

    public Hsl(Color c) { 
     DmcNumber = "unknown"; 
     Color = c; 
     Hue = c.GetHue(); 
     Saturation = c.GetSaturation(); 
     Brightness = c.GetBrightness(); 
     Count = 0; 
    } 

    public Hsl(string dmc, int r, int g, int b) 
     : this(Color.FromArgb(r, g, b)) 
    { 
     DmcNumber = dmc; 
    } 

    private static float AngleDifference(float a1, float a2) { 
     float a = Math.Abs(a1 - a2); 
     if (a > 180f) { 
      a = 360f - a; 
     } 
     return a/180f; 
    } 

    public float GetDistance(Hsl other) { 
     return 
      AngleDifference(Hue, other.Hue) * 3.0f + 
      Math.Abs(Saturation - other.Saturation) + 
      Math.Abs(Brightness - other.Brightness) * 4.0f; 
    } 

    public Hsl GetNearest(IEnumerable<Hsl> dmcColors) { 
     Hsl nearest = null; 
     float nearestDistance = float.MaxValue; 
     foreach (Hsl dmc in dmcColors) { 
      float distance = GetDistance(dmc); 
      if (distance < nearestDistance) { 
       nearestDistance = distance; 
       nearest = dmc; 
      } 
     } 
     return nearest; 
    } 

} 

Mã này thiết lập một (giảm nặng nề) danh sách các Màu DMC, tải hình ảnh, đếm màu, giảm bảng màu và chuyển đổi hình ảnh. Tất nhiên, bạn cũng muốn lưu thông tin từ bảng màu bị giảm ở đâu đó.

Hsl[] dmcColors = { 
    new Hsl("blanc", 255, 255, 255), 
    new Hsl("310", 0, 0, 0), 
    new Hsl("317", 167, 139, 136), 
    new Hsl("318", 197, 198, 190), 
    new Hsl("322", 81, 109, 135), 
    new Hsl("336", 36, 73, 103), 
    new Hsl("413", 109, 95, 95), 
    new Hsl("414", 167, 139, 136), 
    new Hsl("415", 221, 221, 218), 
    new Hsl("451", 179, 151, 143), 
    new Hsl("452", 210, 185, 175), 
    new Hsl("453", 235, 207, 185), 
    new Hsl("503", 195, 206, 183), 
    new Hsl("504", 206, 221, 193), 
    new Hsl("535", 85, 85, 89) 
}; 

Bitmap image = (Bitmap)Image.FromFile(@"d:\temp\pattern.jpg"); 

// count colors used 
List<Hsl> usage = new List<Hsl>(); 
for (int y = 0; y < image.Height; y++) { 
    for (int x = 0; x < image.Width; x++) { 
     Hsl color = new Hsl(image.GetPixel(x, y)); 
     Hsl nearest = color.GetNearest(dmcColors); 
     int index = usage.FindIndex(h => h.Color.Equals(nearest.Color)); 
     if (index != -1) { 
      usage[index].Count++; 
     } else { 
      nearest.Count = 1; 
      usage.Add(nearest); 
     } 
    } 
} 

// reduce number of colors by picking the most used 
Hsl[] reduced = usage.OrderBy(c => -c.Count).Take(5).ToArray(); 

// convert image 
for (int y = 0; y < image.Height; y++) { 
    for (int x = 0; x < image.Width; x++) { 
     Hsl color = new Hsl(image.GetPixel(x, y)); 
     Hsl nearest = color.GetNearest(reduced); 
     image.SetPixel(x, y, nearest.Color); 
    } 
} 

image.Save(@"d:\temp\pattern.png", System.Drawing.Imaging.ImageFormat.Png); 
Các vấn đề liên quan