gpt4 book ai didi

opencv - 缩小/限制图像调色板的算法

转载 作者:太空宇宙 更新时间:2023-11-03 21:27:52 24 4
gpt4 key购买 nike

作为输入数据,我有一个 24 位 RGB 图像和一个具有 2..20 种固定颜色的调色板。这些颜色绝不会在整个颜色范围内有规律地分布。

现在我必须修改输入图像的颜色,以便只使用给定调色板的颜色 - 使用调色板中最接近原始颜色的颜色(不是数学上最接近,而是人类视觉印象)。所以我需要的是一种算法,它使用输入颜色并在目标调色板中找到视觉上最适合该颜色的颜色。请注意:我不是在寻找愚蠢的比较/差异算法,而是在寻找真正融合了颜色对人类印象的算法!

因为这是已经应该完成的事情,并且因为我不想再次重新发明轮子:是否有一些示例源代码可以完成这项工作?在最好的情况下,它实际上是一段代码,而不是指向一个灾难性的巨大库的链接;-)

(我猜OpenCV没有提供这样的功能?)

谢谢

最佳答案

你应该看看 Lab color space .它的设计使色彩空间中的距离等于感知距离。因此,一旦您转换了图像,您就可以像之前那样计算距离,但从感知的角度来看应该会得到更好的结果。在 OpenCV 中,您可以使用 cvtColor(source, destination, CV_BGR2Lab) 函数。

另一个想法是使用 dithering .这个想法是使用相邻像素混合缺失的颜色。一个流行的算法是 Floyd-Steinberg dithering .

这是我的一个例子,我将使用 k-means 的优化调色板与 Lab 色彩空间和 floyd steinberg 抖动相结合:

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

using namespace cv;
using namespace std;

cv::Mat floydSteinberg(cv::Mat img, cv::Mat palette);
cv::Vec3b findClosestPaletteColor(cv::Vec3b color, cv::Mat palette);

int main(int argc, char** argv)
{
// Number of clusters (colors on result image)
int nrColors = 18;

cv::Mat imgBGR = imread(argv[1],1);

cv::Mat img;
cvtColor(imgBGR, img, CV_BGR2Lab);


cv::Mat colVec = img.reshape(1, img.rows*img.cols); // change to a Nx3 column vector

cv::Mat colVecD;
colVec.convertTo(colVecD, CV_32FC3, 1.0); // convert to floating point


cv::Mat labels, centers;
cv::kmeans(colVecD, nrColors, labels,
cv::TermCriteria(CV_TERMCRIT_ITER, 100, 0.1),
3, cv::KMEANS_PP_CENTERS, centers); // compute k mean centers

// replace pixels by there corresponding image centers
cv::Mat imgPosterized = img.clone();
for(int i = 0; i < img.rows; i++ )
for(int j = 0; j < img.cols; j++ )
for(int k = 0; k < 3; k++)
imgPosterized.at<Vec3b>(i,j)[k] = centers.at<float>(labels.at<int>(j+img.cols*i),k);

// convert palette back to uchar
cv::Mat palette;
centers.convertTo(palette,CV_8UC3,1.0);

// call floyd steinberg dithering algorithm
cv::Mat fs = floydSteinberg(img, palette);

cv::Mat imgPosterizedBGR, fsBGR;
cvtColor(imgPosterized, imgPosterizedBGR, CV_Lab2BGR);
cvtColor(fs, fsBGR, CV_Lab2BGR);


imshow("input",imgBGR); // original image
imshow("result",imgPosterizedBGR); // posterized image
imshow("fs",fsBGR); // floyd steinberg dithering
waitKey();

return 0;
}

cv::Mat floydSteinberg(cv::Mat imgOrig, cv::Mat palette)
{
cv::Mat img = imgOrig.clone();
cv::Mat resImg = img.clone();
for(int i = 0; i < img.rows; i++ )
for(int j = 0; j < img.cols; j++ )
{
cv::Vec3b newpixel = findClosestPaletteColor(img.at<Vec3b>(i,j), palette);
resImg.at<Vec3b>(i,j) = newpixel;

for(int k=0;k<3;k++)
{
int quant_error = (int)img.at<Vec3b>(i,j)[k] - newpixel[k];
if(i+1<img.rows)
img.at<Vec3b>(i+1,j)[k] = min(255,max(0,(int)img.at<Vec3b>(i+1,j)[k] + (7 * quant_error) / 16));
if(i-1 > 0 && j+1 < img.cols)
img.at<Vec3b>(i-1,j+1)[k] = min(255,max(0,(int)img.at<Vec3b>(i-1,j+1)[k] + (3 * quant_error) / 16));
if(j+1 < img.cols)
img.at<Vec3b>(i,j+1)[k] = min(255,max(0,(int)img.at<Vec3b>(i,j+1)[k] + (5 * quant_error) / 16));
if(i+1 < img.rows && j+1 < img.cols)
img.at<Vec3b>(i+1,j+1)[k] = min(255,max(0,(int)img.at<Vec3b>(i+1,j+1)[k] + (1 * quant_error) / 16));
}
}
return resImg;
}

float vec3bDist(cv::Vec3b a, cv::Vec3b b)
{
return sqrt( pow((float)a[0]-b[0],2) + pow((float)a[1]-b[1],2) + pow((float)a[2]-b[2],2) );
}

cv::Vec3b findClosestPaletteColor(cv::Vec3b color, cv::Mat palette)
{
int i=0;
int minI = 0;
cv::Vec3b diff = color - palette.at<Vec3b>(0);
float minDistance = vec3bDist(color, palette.at<Vec3b>(0));
for (int i=0;i<palette.rows;i++)
{
float distance = vec3bDist(color, palette.at<Vec3b>(i));
if (distance < minDistance)
{
minDistance = distance;
minI = i;
}
}
return palette.at<Vec3b>(minI);
}

关于opencv - 缩小/限制图像调色板的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18379510/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com