更多细节:这些颜色来自具有不同颜色的凝胶管的照片。我有5个不同颜色的管子,每个代表5个级别中的1个。我想拍摄其他样品的照片,并在计算机上通过比较颜色来评估该样品属于哪个级别,并且我还想知道其近似百分比。我希望程序能够像这样实现:http://www.colortools.net/color_matcher.html 如果您能告诉我需要采取哪些步骤,即使这些步骤是我需要手动思考和执行的事情,也将非常有帮助。
def lum(c):
def factor(component):
component = component / 255;
if (component <= 0.03928):
component = component / 12.92;
else:
component = math.pow(((component + 0.055) / 1.055), 2.4);
return component
components = [factor(ci) for ci in c]
return (components[0] * 0.2126 + components[1] * 0.7152 + components[2] * 0.0722) + 0.05;
def color_distance(c1, c2):
l1 = lum(c1)
l2 = lum(c2)
higher = max(l1, l2)
lower = min(l1, l2)
return (higher - lower) / higher
c1 = ImageColor.getrgb('white')
c2 = ImageColor.getrgb('yellow')
print(color_distance(c1, c2))
0.0687619047619048
ImageColor
的起源是什么?编辑 我找到了,它是 from PIL import ImageColor
。 - ademar111190Android ColorUtils API RGBToHSL: 我有两个int型的argb颜色(color1,color2),希望获取两种颜色之间的距离/差异。我所做的是:
private float getHue(int color) {
int R = (color >> 16) & 0xff;
int G = (color >> 8) & 0xff;
int B = (color ) & 0xff;
float[] colorHue = new float[3];
ColorUtils.RGBToHSL(R, G, B, colorHue);
return colorHue[0];
}
我使用以下代码来查找两种颜色之间的距离。
private float getDistance(getHue(color1), getHue(color2)) {
float avgHue = (hue1 + hue2)/2;
return Math.abs(hue1 - avgHue);
}
我在我的安卓设备中使用了这个,虽然不建议使用RGB颜色空间,但似乎还算满意:
public double colourDistance(int red1,int green1, int blue1, int red2, int green2, int blue2)
{
double rmean = ( red1 + red2 )/2;
int r = red1 - red2;
int g = green1 - green2;
int b = blue1 - blue2;
double weightR = 2 + rmean/256;
double weightG = 4.0;
double weightB = 2 + (255-rmean)/256;
return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b);
}
double maxColDist = 764.8339663572415;
double d1 = colourDistance(red1,green1,blue1,red2,green2,blue2);
String s1 = (int) Math.round(((maxColDist-d1)/maxColDist)*100) + "% match";
它的表现还不错。
<script>
var constants = {
canvasWidth: 700, // In pixels.
canvasHeight: 600, // In pixels.
colorMap: new Array()
};
// -----------------------------------------------------------------------------------------------------
function fillcolormap(imageObj1) {
function rgbtoxyz(red1,green1,blue1){ // a converter for converting rgb model to xyz model
var red2 = red1/255;
var green2 = green1/255;
var blue2 = blue1/255;
if(red2>0.04045){
red2 = (red2+0.055)/1.055;
red2 = Math.pow(red2,2.4);
}
else{
red2 = red2/12.92;
}
if(green2>0.04045){
green2 = (green2+0.055)/1.055;
green2 = Math.pow(green2,2.4);
}
else{
green2 = green2/12.92;
}
if(blue2>0.04045){
blue2 = (blue2+0.055)/1.055;
blue2 = Math.pow(blue2,2.4);
}
else{
blue2 = blue2/12.92;
}
red2 = (red2*100);
green2 = (green2*100);
blue2 = (blue2*100);
var x = (red2 * 0.4124) + (green2 * 0.3576) + (blue2 * 0.1805);
var y = (red2 * 0.2126) + (green2 * 0.7152) + (blue2 * 0.0722);
var z = (red2 * 0.0193) + (green2 * 0.1192) + (blue2 * 0.9505);
var xyzresult = new Array();
xyzresult[0] = x;
xyzresult[1] = y;
xyzresult[2] = z;
return(xyzresult);
} //end of rgb_to_xyz function
function xyztolab(xyz){ //a convertor from xyz to lab model
var x = xyz[0];
var y = xyz[1];
var z = xyz[2];
var x2 = x/95.047;
var y2 = y/100;
var z2 = z/108.883;
if(x2>0.008856){
x2 = Math.pow(x2,1/3);
}
else{
x2 = (7.787*x2) + (16/116);
}
if(y2>0.008856){
y2 = Math.pow(y2,1/3);
}
else{
y2 = (7.787*y2) + (16/116);
}
if(z2>0.008856){
z2 = Math.pow(z2,1/3);
}
else{
z2 = (7.787*z2) + (16/116);
}
var l= 116*y2 - 16;
var a= 500*(x2-y2);
var b= 200*(y2-z2);
var labresult = new Array();
labresult[0] = l;
labresult[1] = a;
labresult[2] = b;
return(labresult);
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageX = 0;
var imageY = 0;
context.drawImage(imageObj1, imageX, imageY, 240, 140);
var imageData = context.getImageData(0, 0, 240, 140);
var data = imageData.data;
var n = data.length;
// iterate over all pixels
var m = 0;
for (var i = 0; i < n; i += 4) {
var red = data[i];
var green = data[i + 1];
var blue = data[i + 2];
var xyzcolor = new Array();
xyzcolor = rgbtoxyz(red,green,blue);
var lab = new Array();
lab = xyztolab(xyzcolor);
constants.colorMap.push(lab); //fill up the colormap array with lab colors.
}
}
// -----------------------------------------------------------------------------------------------------
function colorize(pixqty) {
function deltae94(lab1,lab2){ //calculating Delta E 1994
var c1 = Math.sqrt((lab1[1]*lab1[1])+(lab1[2]*lab1[2]));
var c2 = Math.sqrt((lab2[1]*lab2[1])+(lab2[2]*lab2[2]));
var dc = c1-c2;
var dl = lab1[0]-lab2[0];
var da = lab1[1]-lab2[1];
var db = lab1[2]-lab2[2];
var dh = Math.sqrt((da*da)+(db*db)-(dc*dc));
var first = dl;
var second = dc/(1+(0.045*c1));
var third = dh/(1+(0.015*c1));
var deresult = Math.sqrt((first*first)+(second*second)+(third*third));
return(deresult);
} // end of deltae94 function
var lab11 = new Array("80","-4","21");
var lab12 = new Array();
var k2=0;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, 240, 140);
var data = imageData.data;
for (var i=0; i<pixqty; i++) {
lab12 = constants.colorMap[i];
var deltae = deltae94(lab11,lab12);
if (deltae <= 10) {
data[i*4] = 255;
data[(i*4)+1] = 0;
data[(i*4)+2] = 0;
k2++;
} // end of if
} //end of for loop
context.clearRect(0,0,240,140);
alert(k2);
context.putImageData(imageData,0,0);
}
// -----------------------------------------------------------------------------------------------------
$(window).load(function () {
var imageObj = new Image();
imageObj.onload = function() {
fillcolormap(imageObj);
}
imageObj.src = './mixcolor.png';
});
// ---------------------------------------------------------------------------------------------------
var pixno2 = 240*140;
</script>
1/3
和 16/116
都计算为 0
,这几乎肯定不是你想要的结果。可能你的算法是正确的,但你的代码肯定不对。 - Dawood ibn Kareem我猜你最终想要分析整张图片,对吧?这样你就可以检查与身份颜色矩阵之间的最小/最大差异。
大多数用于处理图形的数学运算使用矩阵,因为使用它们的可能算法通常比经典的逐点距离和比较计算更快。(例如,用于使用DirectX、OpenGL等操作)
所以我认为你应该从这里开始:
http://en.wikipedia.org/wiki/Identity_matrix
http://en.wikipedia.org/wiki/Matrix_difference_equation
...正如Beska在上面的评论中所说:
这可能不会给出最好的“可见”差异...
这也意味着,如果您正在处理图像,则算法取决于您对“相似”的定义。
比较颜色的唯一“正确”方法是使用CIELab或CIELuv中的deltaE。
但对于许多应用程序,我认为这是一个足够好的近似:
distance = 3 * |dR| + 4 * |dG| + 3 * |dB|
我认为在比较颜色时,加权曼哈顿距离更有意义。请记住,颜色原色只存在于我们的头脑中,它们没有任何物理意义。 CIELab和CIELuv是从我们对颜色的感知进行统计建模的。
如果想要快速且简单的话,可以这样做
import java.awt.Color;
private Color dropPrecision(Color c,int threshold){
return new Color((c.getRed()/threshold),
(c.getGreen()/threshold),
(c.getBlue()/threshold));
}
public boolean inThreshold(Color _1,Color _2,int threshold){
return dropPrecision(_1,threshold)==dropPrecision(_2,threshold);
}
利用整数除法对颜色进行量化。
Swift 5答案
我发现这个线程是因为我需要一个Swift版本的这个问题。由于没有人回答解决方案,这里是我的解决方案:
extension UIColor {
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
}
func isSimilar(to colorB: UIColor) -> Bool {
let rgbA = self.rgba
let rgbB = colorB.rgba
let diffRed = abs(CGFloat(rgbA.red) - CGFloat(rgbB.red))
let diffGreen = abs(rgbA.green - rgbB.green)
let diffBlue = abs(rgbA.blue - rgbB.blue)
let pctRed = diffRed
let pctGreen = diffGreen
let pctBlue = diffBlue
let pct = (pctRed + pctGreen + pctBlue) / 3 * 100
return pct < 10 ? true : false
}
}
使用方法:
let black: UIColor = UIColor.black
let white: UIColor = UIColor.white
let similar: Bool = black.isSimilar(to: white)
我设置少于10%的差异以返回类似的颜色,但您可以自定义此内容。
import sys
import matplotlib.colors as mc
import numpy as np
from scipy.spatial import KDTree
import cv2
class ColourNamer:
def __init__(self):
self.clut = {}
self.clut_list = []
self.clut_tree = None
for name in mc.XKCD_COLORS:
rgb = mc.to_rgb(mc.XKCD_COLORS[name])
lab = cv2.cvtColor(np.single([[rgb]]), cv2.COLOR_RGB2Lab)[0][0]
self.clut[tuple(lab)] = name[5:]
self.clut_list = list(self.clut.keys())
self.clut_tree = KDTree(self.clut_list)
def name(self, rgb):
lab = tuple(cv2.cvtColor(np.single([[rgb]]), cv2.COLOR_RGB2Lab)[0][0])
dist, point = self.clut_tree.query(lab, 1)
idx = int(point)
key = self.clut_list[idx]
return self.clut[key]
def hex_to_rgb(self, value): # return normative rgb tuple.
value = value.lstrip('#')
lv = len(value) #6 = 8 bit, 12 = 16 bit.
ints = tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))
return tuple(a / 65536 if lv == 12 else a/256 for a in ints)
if __name__ == '__main__':
cn = ColourNamer()
if len(sys.argv) > 0:
hex_c = sys.argv[1]
print(cn.name(cn.hex_to_rgb(hex_c)))
$python colour.py #fe3288
strong pink
$python colour.py #134323
evergreen