我正在做一个项目,该项目涉及根据某些因素将颜色从白色变为深棕色的纸条,我需要编写一个能够对这种颜色进行分类的应用程序。我已经在 OpenCV 中编写了它的特征识别部分,但是我在考虑不同的照明条件时遇到了麻烦。我已经包含了一个包含 6 种不同颜色的矩形:黑色、白色和 4 种不同的灰色阴影,以帮助我完成此过程。但是,我仍在努力获得指标的真实颜色。谁能指出我正确的方向?谢谢。
1 回答
这是一个有趣的任务。您可以尝试从一些简单的方法开始,例如使用线性代数和最小二乘法。
我们可以将真实颜色和注册颜色视为 3D 向量(我假设您使用 RGB 或其他颜色空间中的彩色图像)并将光照效果视为矩阵运算符 (3x3)。
每对颜色都会创建以下形式的约束:
,
你要找的算子在哪里,
是真实的颜色,
是观察到的颜色。
你可以用另一种形式重写这些约束:
的组件在哪里
(观察到的颜色的符号是类似的)。
这种形式允许我们简单地通过堆叠矩阵来组合多个观察结果。您需要至少 3 种颜色匹配来准确估计运算符,如果您想对噪声和其他不需要的影响具有鲁棒性,则需要更多颜色匹配。
根据您的观察形成矩阵后,您可以以最小二乘方式求解一组线性方程以获得您的运算符(从真实颜色映射到观察到的颜色)。
一旦你估计了算子,你就可以对你观察到的任何颜色进行预乘以得到真实的颜色。
这是一种简单易懂且有效的方法,但也有一些缺点。
首先 - 它假设真实颜色和观察到的颜色之间存在线性关系,这可能是一个不正确的假设(我没有做过实验来检查它)。
此外,即使照明充当线性算子 - 由于相机动态范围是固定的 - 一旦某些颜色由于明亮的照明而超出范围,您也可能会遇到问题,因为这会产生剪裁使算子非线性。
此外,您应该仔细选择标记的颜色(我会选择具有不同色调的颜色来捕捉色彩空间的基础,此外它们应该在动态范围的中间以减少超出范围的可能性)。不要忘记,如果您的颜色分量过于相关(例如,如果您使用灰色阴影) - 观察矩阵可能会失去等级并变得奇异,这将使求解A的元素变得不可能/毫无意义。
我制作了一个简单的 python 脚本来检查我描述的运算符是否可以在简单的条件下估计(均匀 2 倍变暗)。它也可用于试验标记的不同颜色。
import numpy as np
# choose colors for marker
Cr = np.array([[10, 200, 30],
[40, 50, 160],
[10, 80, 90],
[150, 60, 10]], dtype = np.float32)
# simulate effect from light
Co = (Cr/2)
# form a set of constraints for a color pair
def genConstr(pt):
constr = np.zeros((3, 9), dtype = np.float32)
constr[0, 0:3] = pt
constr[1, 3:6] = pt
constr[2, 6:9] = pt
return constr
# form constraints for all colors on marker
cs = np.zeros((0, 9), dtype = np.float32)
for i in xrange(Cr.shape[0]):
cs = np.vstack((cs, genConstr(Cr[i, :])))
# estimate operator
Ai = np.linalg.lstsq(cs, Co.flatten())[0].reshape((3, 3))
A = np.linalg.inv(Ai)
#display results
print 'operator:'
print A
print ''
print 'reconstructed colors:'
for i in xrange(Co.shape[0]):
print A.dot(Co[i])
它产生以下结果:
operator:
[[ 2.00000000e+00 -3.12988124e-16 -3.83156015e-16]
[ -1.77322970e-32 2.00000000e+00 -3.60822483e-16]
[ 9.82882077e-17 -4.07302066e-16 2.00000000e+00]]
reconstructed colors:
[ 10. 200. 30.]
[ 40. 50. 160.]
[ 10. 80. 90.]
[ 150. 60. 10.]
如您所见,估计的算子非常接近理论值(主对角线为 2s),并且真实颜色被正确重建。