2009-08-06 52 views
6

Tôi muốn nội suy màu trơn tru từ màu A (gọi màu đỏ) thành màu C (gọi là màu xanh lá cây) đi qua màu B (gọi là vàng), dựa trên giá trị của một biến nhất định.Nội suy màu giữa 3 màu trong .NET

Nếu biến = 100, tôi muốn màu xanh lá cây. Nếu biến = 50, tôi muốn màu vàng nguyên chất. Nếu biến = 0, tôi muốn màu đỏ tinh khiết.

Tôi hiểu rằng bạn có thể xử lý từng bộ ba RGB dưới dạng tọa độ trong không gian 3 chiều. Những gì tôi đang tìm kiếm là một thủ thuật nội suy tuyến tính nhanh và bẩn, hoạt động hiệu quả với bố cục cụ thể của loại màu .NET (các giá trị riêng biệt cho ARGB, v.v.).

+1

Nó không thể được tuyến tính với ba điểm ngẫu nhiên – RBarryYoung

Trả lời

13

Trước tiên, bạn yêu cầu nội suy tuyến tính nhưng bạn không chỉ định màu B đó sống trên đường giữa màu A và màu C; Điều này là cần thiết. Thứ hai, bạn đã không chỉ định nhưng tôi sẽ làm cho một giả định đơn giản hóa rằng màu B là điểm giữa của đường thẳng giữa màu A và màu C; mã sau đây có thể dễ dàng sửa đổi nếu điều này không đúng. Cuối cùng, tôi đã thay đổi giả thiết của bạn rằng tham số là một số nguyên giữa 0 và một trăm là số nguyên giữa số không và một. Mã dễ viết hơn và dễ hiểu hơn trong trường hợp thứ hai, và vẫn có thể được sử dụng với trường hợp cũ (chia đầu vào của bạn cho một trăm).

class ColorInterpolator { 
    delegate byte ComponentSelector(Color color); 
    static ComponentSelector _redSelector = color => color.R; 
    static ComponentSelector _greenSelector = color => color.G; 
    static ComponentSelector _blueSelector = color => color.B; 

    public static Color InterpolateBetween(
     Color endPoint1, 
     Color endPoint2, 
     double lambda) { 
     if (lambda < 0 || lambda > 1) { 
      throw new ArgumentOutOfRangeException("lambda"); 
     } 
     Color color = Color.FromRgb(
      InterpolateComponent(endPoint1, endPoint2, lambda, _redSelector), 
      InterpolateComponent(endPoint1, endPoint2, lambda, _greenSelector), 
      InterpolateComponent(endPoint1, endPoint2, lambda, _blueSelector) 
     ); 

     return color; 
    } 

    static byte InterpolateComponent(
     Color endPoint1, 
     Color endPoint2, 
     double lambda, 
     ComponentSelector selector) { 
     return (byte)(selector(endPoint1) 
      + (selector(endPoint2) - selector(endPoint1)) * lambda); 
    } 
} 

Làm cách nào để bạn sửa đổi điều này nếu màu B không phải là điểm giữa màu A và màu C? Cách dễ nhất là như sau. Nếu tham số (cái tôi gọi là "lambda") nhỏ hơn 0.5, nhân lambda bằng hai và trả về màu nội suy giữa màu A và màu B. Nếu tham số lớn hơn 0.5, nhân lambda bằng hai và trừ một (bản đồ này) [0.5, 1] lên [0, 1]) và trả lại màu nội suy giữa màu B và màu C.

Nếu bạn không thích yêu cầu màu B sống trên dòng giữa màu A và màu C, thì bạn có thể sử dụng chính xác sửa đổi Tôi chỉ mô tả để thực hiện một nội suy tuyến tính từng phần giữa các màu.

Cuối cùng, bạn không chỉ định nếu bạn muốn nội suy giá trị alpha được gọi là ('A' trong "ARGB"). Đoạn mã trên cũng dễ dàng sửa đổi để xử lý tình huống này. Thêm một số khác ComponentSelector được định nghĩa là color => color.A, sử dụng InterpolateComponent để nội suy giá trị này và sử dụng quá tải Color.FromArgb(int, int, int, int) của Color.FromArgb.

+0

Cảm ơn bạn đã phản hồi chi tiết. Chính xác những gì tôi đang tìm kiếm! – user144051

+0

Đối với một giải pháp chung chung hơn, nó có thể là đáng giá [nhìn vào câu trả lời của tôi về một câu hỏi trùng lặp] (http://stackoverflow.com/a/13253304/590790). –

1

Một cách khác để pha trộn màu sắc sử dụng phân phối Gaussian như thế này (bất kỳ số lượng màu sắc cho một loạt các 0,0-1,0, để tăng trộn tăng giá trị sigma_2)

public static Color InterpolateColor(Color[] colors, double x) 
{ 
    double r = 0.0, g = 0.0, b = 0.0; 
    double total = 0.0; 
    double step = 1.0/(double)(colors.Length - 1); 
    double mu = 0.0; 
    double sigma_2 = 0.035; 

    foreach (Color color in colors) 
    {     
     total += Math.Exp(-(x - mu) * (x - mu)/(2.0 * sigma_2))/Math.Sqrt(2.0 * Math.PI * sigma_2); 
     mu += step; 
    } 

    mu = 0.0; 
    foreach(Color color in colors) 
    {     
     double percent = Math.Exp(-(x - mu) * (x - mu)/(2.0 * sigma_2))/Math.Sqrt(2.0 * Math.PI * sigma_2); 
     mu += step; 

     r += color.R * percent/total; 
     g += color.G * percent/total; 
     b += color.B * percent/total; 
    } 

    return Color.FromArgb(255, (int)r, (int)g, (int)b); 
} 

Thông tin thêm http://en.wikipedia.org/wiki/Normal_distribution

Mẫu pha trộn 3 màu:

enter image description here

Các vấn đề liên quan