Python 3.x 将RGB数据映射到图例中的值

Python 3.x 将RGB数据映射到图例中的值,python-3.x,opencv,image-processing,computer-vision,heatmap,Python 3.x,Opencv,Image Processing,Computer Vision,Heatmap,这是我上一个问题的后续问题 我一直在尝试将热图中的颜色数据转换为RGB值 在下图中,左侧是源图像面板D中的子图。它有6 x 6个单元格(6行6列)。在右边,我们看到二值化图像,在运行下面的代码后单击的单元格中高亮显示白色。运行代码的输入如下图所示。输出是(平均值=[27.72 26.83 144.17])是单元格中BGR颜色的平均值,在下图右侧以白色突出显示 作为对我前面问题的回答,提供了一个非常好的解决方案,如下() 图例中每个单元格/每种颜色从左到右的平均值: mean = [ 82.

这是我上一个问题的后续问题

我一直在尝试将热图中的颜色数据转换为RGB值

在下图中,左侧是源图像面板D中的子图。它有6 x 6个单元格(6行6列)。在右边,我们看到二值化图像,在运行下面的代码后单击的单元格中高亮显示白色。运行代码的输入如下图所示。输出是
(平均值=[27.72 26.83 144.17])
是单元格中BGR颜色的平均值,在下图右侧以白色突出显示

作为对我前面问题的回答,提供了一个非常好的解决方案,如下()

图例中每个单元格/每种颜色从左到右的平均值:

mean =  [ 82.15 174.95  33.66]
mean =  [45.55 87.01 17.51]
mean =  [8.88 8.61 5.97]
mean =  [16.79 17.96 74.46]
mean =  [ 35.59  30.53 167.14]
mean =  [ 37.9   32.39 233.74]
mean =  [120.29 118.   240.34]
mean =  [238.33 239.56 248.04]

您可以尝试应用分段方法,在颜色之间进行成对转换:

c[i->i+1](t)=t*(R[i+1],G[i+1],B[i+1])+(1-t)*(R[i],G[i],B[i]) 
对这些值执行相同的操作:

val[i->i+1](t)=t*val[i+1]+(1-t)*val[i]
式中,i-图例比例中的颜色索引,t-范围为[0:1]的参数

所以,有两个值的连续映射,只需要找到最接近样本的颜色参数i和t,并从映射中找到值

更新:

要查找颜色参数,可以将每对相邻图例颜色视为一对3d点,将查询到的颜色视为外部3d点。现在你只需要找到从外部点到直线的垂直长度,然后,在图例颜色对上迭代,找到最短的垂直线(现在你有了i)

然后找到垂线和直线的交点。该点将位于距线路起点的距离A处,如果线路长度为L,则参数值t=A/L

更新2:

用于说明分段方法的简单蛮力解决方案:

#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char* argv[])
{
    Mat Image=cv::Mat::zeros(100,250,CV_32FC3);
    std::vector<cv::Scalar> Legend;
    Legend.push_back(cv::Scalar(82.15,174.95,33.66));
    Legend.push_back(cv::Scalar(45.55, 87.01, 17.51));
    Legend.push_back(cv::Scalar(8.88, 8.61, 5.97));
    Legend.push_back(cv::Scalar(16.79, 17.96, 74.46));
    Legend.push_back(cv::Scalar(35.59, 30.53, 167.14));
    Legend.push_back(cv::Scalar(37.9, 32.39, 233.74));
    Legend.push_back(cv::Scalar(120.29, 118., 240.34));
    Legend.push_back(cv::Scalar(238.33, 239.56, 248.04));

    std::vector<float> Values;
    Values.push_back(-4);
    Values.push_back(-2);
    Values.push_back(0);
    Values.push_back(2);
    Values.push_back(4);
    Values.push_back(8);
    Values.push_back(16);
    Values.push_back(32);

    int w = 30;
    int h = 10;

    for (int i = 0; i < Legend.size(); ++i)
    {
        cv::rectangle(Image, Rect(i * w, 0, w, h), Legend[i]/255, -1);
    }

    std::vector<cv::Scalar> Smooth_Legend;
    std::vector<float> Smooth_Values;
    for (int i = 0; i < Legend.size()-1; ++i)
    {
        cv::Scalar c1 = Legend[i];
        cv::Scalar c2 = Legend[i + 1];
        float v1 = Values[i];
        float v2 = Values[i+1];
        for (int j = 0; j < w; ++j)
        {
            float t = (float)j / (float)w;
            Scalar c = c2 * t + c1 * (1 - t);
            float v = v2 * t + v1 * (1 - t);
            float x = i * w + j;
            line(Image, Point(x, h), Point(x, h + h), c/255, 1);
            Smooth_Values.push_back(v);
            Smooth_Legend.push_back(c);
        }
    }

    Scalar qp = cv::Scalar(5, 0, 200);
    float d_min = FLT_MAX;
    int ind = -1;
    for (int i = 0; i < Smooth_Legend.size(); ++i)
    {
        float d = cv::norm(qp- Smooth_Legend[i]);
        if (d < d_min)
        {
            ind = i;
            d_min = d;
        }
    }
    std::cout << Smooth_Values[ind] << std::endl;

    line(Image, Point(ind, 3 * h), Point(ind, 4 * h), Scalar::all(255), 2);
    circle(Image, Point(ind, 4 * h), 3, qp/255,-1);
    putText(Image, std::to_string(Smooth_Values[ind]), Point(ind, 70), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0.5, 0.5), 0.002);


    cv::imshow("Legend", Image);
    cv::imwrite("result.png", Image*255);
    cv::waitKey();

}
#包括“opencv2/opencv.hpp”
#包括
#包括
使用名称空间std;
使用名称空间cv;
int main(int argc,char*argv[])
{
Mat Image=cv::Mat::zeros(100250,cv_32FC3);
std::矢量图例;
图例。推回(cv::标量(82.15174.95,33.66));
图例。推回(cv::标量(45.55,87.01,17.51));
图例。推回(cv::标量(8.88,8.61,5.97));
图例。推回(cv::标量(16.79,17.96,74.46));
图例。推回(cv::标量(35.59,30.53,167.14));
图例。推回(cv::标量(37.9,32.39,233.74));
图例。推回(cv::标量(120.29118,240.34));
图例。推回(cv::标量(238.33239.56248.04));
std::向量值;
值。向后推_(-4);
值。向后推_(-2);
值。向后推_(0);
值。推回(2);
值。推回(4);
值。推回(8);
值。推回(16);
值。推回(32);
int w=30;
int h=10;
对于(int i=0;i你能测量颜色条(图例)的RGB值吗还有?如果是这样,那么这个问题将大大简化为如何在勒根集中找到与数据集中每个RGB值最接近的RGB值的问题。或者甚至可能是如何插值。但是,由于已经解决了这一问题,因此您可以去掉所有图像数据。@CrisLuengo非常感谢您的回答。请检查editSmorodov,好吗请详细解释一下如何找到颜色参数?可能这也是我的答案。很抱歉,我没有完全理解。如果我从图像中单元格的RGB值矩阵和另一个带有图例RGB值的数组开始,会有帮助吗?我希望一步一步地做。所有这些对我来说都是新的,所以对我来说有点困难让我在一个更新中理解。添加了一个简单的蛮力示例。通过改变w,您可以调整近似精度。如果您想要更高的精度和速度,请转到分析方式而不是蛮力。它很容易转换,请检查updete。
val[i->i+1](t)=t*val[i+1]+(1-t)*val[i]
#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char* argv[])
{
    Mat Image=cv::Mat::zeros(100,250,CV_32FC3);
    std::vector<cv::Scalar> Legend;
    Legend.push_back(cv::Scalar(82.15,174.95,33.66));
    Legend.push_back(cv::Scalar(45.55, 87.01, 17.51));
    Legend.push_back(cv::Scalar(8.88, 8.61, 5.97));
    Legend.push_back(cv::Scalar(16.79, 17.96, 74.46));
    Legend.push_back(cv::Scalar(35.59, 30.53, 167.14));
    Legend.push_back(cv::Scalar(37.9, 32.39, 233.74));
    Legend.push_back(cv::Scalar(120.29, 118., 240.34));
    Legend.push_back(cv::Scalar(238.33, 239.56, 248.04));

    std::vector<float> Values;
    Values.push_back(-4);
    Values.push_back(-2);
    Values.push_back(0);
    Values.push_back(2);
    Values.push_back(4);
    Values.push_back(8);
    Values.push_back(16);
    Values.push_back(32);

    int w = 30;
    int h = 10;

    for (int i = 0; i < Legend.size(); ++i)
    {
        cv::rectangle(Image, Rect(i * w, 0, w, h), Legend[i]/255, -1);
    }

    std::vector<cv::Scalar> Smooth_Legend;
    std::vector<float> Smooth_Values;
    for (int i = 0; i < Legend.size()-1; ++i)
    {
        cv::Scalar c1 = Legend[i];
        cv::Scalar c2 = Legend[i + 1];
        float v1 = Values[i];
        float v2 = Values[i+1];
        for (int j = 0; j < w; ++j)
        {
            float t = (float)j / (float)w;
            Scalar c = c2 * t + c1 * (1 - t);
            float v = v2 * t + v1 * (1 - t);
            float x = i * w + j;
            line(Image, Point(x, h), Point(x, h + h), c/255, 1);
            Smooth_Values.push_back(v);
            Smooth_Legend.push_back(c);
        }
    }

    Scalar qp = cv::Scalar(5, 0, 200);
    float d_min = FLT_MAX;
    int ind = -1;
    for (int i = 0; i < Smooth_Legend.size(); ++i)
    {
        float d = cv::norm(qp- Smooth_Legend[i]);
        if (d < d_min)
        {
            ind = i;
            d_min = d;
        }
    }
    std::cout << Smooth_Values[ind] << std::endl;

    line(Image, Point(ind, 3 * h), Point(ind, 4 * h), Scalar::all(255), 2);
    circle(Image, Point(ind, 4 * h), 3, qp/255,-1);
    putText(Image, std::to_string(Smooth_Values[ind]), Point(ind, 70), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0.5, 0.5), 0.002);


    cv::imshow("Legend", Image);
    cv::imwrite("result.png", Image*255);
    cv::waitKey();

}
import cv2
import numpy as np
height=100
width=250
Image = np.zeros((height, width,3), np.float)
legend =  np.array([ (82.15,174.95,33.66),
          (45.55,87.01,17.51),
          (8.88,8.61,5.97),
          (16.79,17.96,74.46),
          ( 35.59,0.53,167.14),
          ( 37.9,32.39,233.74),
          (120.29,118.,240.34),
          (238.33,239.56,248.04)], np.float)

values = np.array([-4,-2,0,2,4,8,16,32], np.float)

# width of cell, also defines number 
# of one segment transituin subdivisions.
# Larger values will give more accuracy, but will woek slower.
w = 30 
# Only fo displaying purpose. Height of bars in result image.
h = 10


# Plot legend cells ( to check correcrness only )
for i in range(len(legend)):
    col=legend[i]
    cv2.rectangle(Image, (i * w, 0, w, h), col/255, -1)

# Start form smoorhed scales for color and according values
Smooth_Legend=[]
Smooth_Values=[]
for i in range(len(legend)-1): # iterate known knots
    c1 = legend[i] # start color point
    c2 = legend[i + 1] # end color point
    v1 = values[i] # start value 
    v2 = values[i+1] # emd va;ie
    for j in range(w): # slide inside [start:end] interval.
        t = float(j) / float(w) # map it to [0:1] interval
        c = c2 * t + c1 * (1 - t) # transition between c1 and c2
        v = v2 * t + v1 * (1 - t) # transition between v1 and v2
        x = i * w + j # global scale coordinate (for drawing)
        cv2.line(Image, (x, h), (x, h + h), c/255, 1) # draw one tick of smoothed scale
        Smooth_Values.append(v) # append smoothed values for next step
        Smooth_Legend.append(c) # append smoothed color for next step

# queried color    
qp = np.array([5, 0, 200])
# initial value for minimal distance set to large value
d_min = 1e7
# index for clolor search
ind = -1
# search for minimal distance from queried color to smoothed scale color
for i in range(len(Smooth_Legend)):
    # distance
    d = cv2.norm(qp-Smooth_Legend[i])
    if (d < d_min):    
        ind = i
        d_min = d
# ind contains index of the closest color in smoothed scale
# and now we can extract according value from smoothed values scale
print(Smooth_Values[ind]) # value mapped to queried color.
# plot pointer (to check ourself)
cv2.line(Image, (ind, 3 * h), (ind, 4 * h), (255,255,255), 2);
cv2.circle(Image, (ind, 4 * h), 3, qp/255,-1);
cv2.putText(Image, str(Smooth_Values[ind]), (ind, 70), cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0.5, 0.5), 1);
# show window
cv2.imshow("Legend", Image)
# save to file
cv2.imwrite("result.png", Image*255)
cv2.waitKey()