很多图像处理算法是以颜色为原理展开的, 因此颜色数目很大程度上决定了算法的运行效率. 如果可以大大降低图像中的颜色数目, 将可以轻松地优化特定的图像处理算法.


1. 简单方法 - 像素除法


使用以下的像素除法公式, 可以将颜色减少 1 / N.

color = color/div*div+div/2\text{color = color/div*div+div/2} color = color/div*div+div/2

若 div 为 8,则原来 RGB 每个通道的 256 种颜色减少为 32 种.

若 div 为 64,则原来 RGB 每个通道的 256 种颜色减少为 4 种,此时三通道所有能表示的颜色为 4 * 4 * 4 = 64 种。

256 种颜色表示的范围是 0~255, 那么分布在这个范围内的数除以 64 之后得到的是 4 个数,也就是 0,1,2,3.

255 / 64 * 64,上面的 4 个数 * 64 = 0,64,128,192

256 / 64 * 64 + 64 / 2,上面 4 个数 + 32 = 32,96,160,224

所以 256 种颜色就减少为 4 种.


2. 将每通道 255 种 colors 减少为固定的 colors


首先明确一下颜色数量 ( 即直方图中的 color bins ) 的概念.

对于 256 种颜色的单通道灰度图像, 计算其直方图后, 直方图中 color bins 的数量为 256, 直方图会统计出每种颜色(可能的取值范围为 0 - 256 ) 在灰度图中出现的次数.

对于 256 种颜色的三通道彩色图像, 其颜色直方图中 color bins 的数量为 256^3 ≈ 16 万, 而原图中就包含着大约 16 万种颜色, 这对于后续的基于颜色的图像处理算法而言有很大的计算量, 因此, 减少颜色数量就显得非常必要了.

每个通道指定固定的 colors

我们可以为每个通道直接指定一个合适的 colors 种类来减少图像中颜色的数量, 比如将每通道 256 种颜色指定为 12 种颜色, 这样对于彩色图像来说, 最大可表示的颜色数量就变成 12^3 = 1728 种.

原图:

使用每通道 12 个 颜色量化图像后可将颜色数目减少为 274 ( 最大可表示为 1728), 效果如下:

可以看到, 274 个直方图 color bins 的色彩仍然得到了很高的视觉质量.

去掉在图像中出现次数很少的颜色

虽然 274 种颜色和 16 万种颜色相比而言确实减少了很多, 但是通过观察这 274 种颜色直方图后可以发现, 有很大一部分 bins 中对应的颜色数量很少, 这意味着这部分颜色在图像中出现的次数很少, 可以去掉这部分颜色, 进一步减少颜色数量.

去掉的颜色会引起图片中出现瑕疵, 如果某个颜色由于出现次数较少需要去掉时, 可以使用出现次数多的颜色中和它最相近的颜色替换它, 这样就可以做到颜色空间的平滑.

最终颜色数目减少为 82 种, 对于后续的图像处理应用效率提升有很大的帮助. 显示效果如下:

可以看到, 和 274 种直方图 color bins 的色彩图相比, 因为只是去除了图像中出现很少的颜色, 因此, 82 种颜色的图像整体效果和 274 种颜色的图像视觉效果差别不大, 依然得到了很高的视觉质量.

代码

为防止伸手党, 代码中贴出了核心的实现细节, 部分关键代码都给出了注释:

/*** \brief: Quantize Color numbers in RGB Color Space*         Default: quantize the color number to 12 with each channel.  * * * \param: img3f - src image, normalized to [0, 1]*         n_colors - color numbers (3 channels) after quantize*         ratio - significant colors' pixels percentage, default = 0.95* * \return: color_q - Finally quantized image*
*/
int Quantize(cv::Mat& img3f, cv::Mat &color_q, double ratio, const int n_colors[3])
{CV_Assert(img3f.data != NULL);int rows = img3f.rows, cols = img3f.cols;int color_bins_quant[3] = {n_colors[0], n_colors[1], n_colors[2]};// color bins weights of channelsint weights[3] = {n_colors[0] * n_colors[0], n_colors[0], 1};  // 12^2, 12, 1cv::Mat idx1i = cv::Mat::zeros(img3f.size(), CV_32S);if (img3f.isContinuous() && idx1i.isContinuous()){cols *= rows;rows = 1;}// First Step: reduce the color bins to fixed bins, 12 // Build color pallet, get every quantized_color's numberstd::map<int, int> pallet;   // (quantized_color, num) pairs in palletint color_val = 0;for (int y = 0; y < rows; y++){const float* imgData = img3f.ptr<float>(y);int* idx = idx1i.ptr<int>(y);for (int x = 0; x < cols; x++, imgData += 3){// color after quantized, eg: 256^3 -> 256 * 256 * 256color_val = (int)(imgData[0]*color_bins_quant[0])*weights[0] + (int)(imgData[1]*color_bins_quant[1])*weights[1] + (int)(imgData[2]*color_bins_quant[2]);pallet[color_val] ++;idx[x] = color_val;  // fill Mat: idx1i}}std::cout << "color reduced first step: " << pallet.size() << std::endl;// Second Step: Reduce more by removing colors rarely appear// Find significant colors, this will cover 95% pixels in image int maxNum = 0;  // colors number left finally, 3 channles total: [10 - 256]{std::vector<std::pair<int, int>> num; // (num, color) pairs in numnum.reserve(pallet.size());for (std::map<int, int>::iterator it = pallet.begin(); it != pallet.end(); it++)num.push_back(std::pair<int, int>(it->second, it->first)); // (color, num) pairs in palletstd::sort(num.begin(), num.end(), std::greater<pair<int, int>>()); // sort with key// remove the colors appear rarelymaxNum = (int)num.size();int maxDropNum = cvRound(rows * cols * (1-ratio));for (int crnt = num[maxNum-1].first; crnt < maxDropNum && maxNum > 1; maxNum--)crnt += num[maxNum - 2].first;std::cout << "color reduced second step: " << maxNum << std::endl;maxNum = std::min(maxNum, 256); // To avoid very rarely caseif (maxNum <= 10)maxNum = std::min(10, (int)num.size());pallet.clear();// Beacuse "maxNum" is the total colors number left finally, and "num" has been sorted// "pallet" contains (color, color_index) pairsfor (int i = 0; i < maxNum; i++)pallet[num[i].second] = num[i].second; // RGB color after quantizedstd::vector<cv::Vec3i> color3i(num.size());for (unsigned int i = 0; i < num.size(); i++){color3i[i][0] = num[i].second / weights[0];color3i[i][1] = num[i].second % weights[0] / weights[1];color3i[i][2] = num[i].second % weights[1];}// reassign the 5% pixels colors to its nearest color which left in histogram binsfor (unsigned int i = maxNum; i < num.size(); i++){int similar_idx = 0, similar_val = INT_MAX;// remained binsfor (int j = 0; j < maxNum; j++){int dist_ij = vecSqrDist<int, 3>(color3i[i], color3i[j]);  // color distance, use vector abs distanceif (dist_ij < similar_val)similar_val = dist_ij, similar_idx = j;}pallet[num[i].second] = pallet[num[similar_idx].second];}}// Finally quantized imagecolor_q = cv::Mat::zeros(img3f.size(), CV_8UC3);  for (int y = 0; y < rows; y++){const float* imgData = img3f.ptr<float>(y);int* idx = idx1i.ptr<int>(y);cv::Vec3b* q = color_q.ptr<cv::Vec3b>(y);for (int x = 0; x < cols; x++, imgData += 3){// quantized image, * 21.3 to make image color brightq[x][0] = (uchar)(pallet[idx[x]] / weights[0]*21.3); q[x][1] = (uchar)(pallet[idx[x]] % weights[0] / weights[1]*21.3);q[x][2] = (uchar)(pallet[idx[x]] % weights[1]*21.3);}}return 0;
}

参考资料

[1]. 减少图像的颜色数量
[2]. Global Contrast based Salient Region detection

RGB 空间颜色量化 - 减少颜色数目相关推荐

  1. xyz坐标图_“色觉地图”的建立(二):辐照度与亮度、rgb空间、“颜色图”的混色方式...

    上篇""色觉地图"的建立(一):光感受器.色匹配实验与CIE RGB坐标系"中说到,人的色觉是线性的,我们可以用叠加原理"混色"--这意味着 ...

  2. 利用几种颜色量化方法提取图片颜色色调

    利用几种颜色量化方法提取图片颜色色调 利用几种颜色量化方法提取图片颜色色调 1 k-means方法(在RGB空间) 2 k-means方法(Lab颜色空间) 3 最小方差量化方法rgb2ind() 4 ...

  3. 颜色量化 matlab,利用几种颜色量化方法提取图片颜色色调

    利用几种颜色量化方法提取图片颜色色调 这里主要用3种方法:包含两种k-means方法和一种matlab自带的最小方差量化方法. 为了方便对比,文中选用梵高的星空(The Starry Night)作为 ...

  4. Python OpenCV应用K均值聚类进行颜色量化

    Python OpenCV应用K均值聚类进行颜色量化 1. 效果图 2. 颜色量化是什么? 3. MiniBatchKMeans & KMeans 4. 源码 参考 在这篇博客文章中,我将向您 ...

  5. EasyExcel 单元格背景颜色、字体颜色使用2种设置颜色方法(IndexedColors中定义的颜色,自定义RGB颜色)实现

    1 Maven配置 <!--hutool工具包--><dependency><groupId>cn.hutool</groupId><artifa ...

  6. OpenCV—python 颜色量化—(255*255*255 颜色量化转成 12*12*12)

    颜色量化 这里的颜色量化主要是用于显著性检测.将255*255*255=16581375 颜色量化转成 12*12*12=1728.以此来减少计算量. 若是查看显著性检测代码,请点击查看原博客:htt ...

  7. photoshop中RGB三色原理及颜色相加相减

    From: http://blog1.poco.cn/myBlogDetail-htx-id-5921820-userid-55622677-pri--n-0.xhtml 一.RGB三色原理 在中学的 ...

  8. K-means聚类颜色量化

    K-means聚类颜色量化 颜色量化 颜色量化是指减少在图像中的颜色数量的压缩过程,是一种对彩色图像进行数字图形处理的常用方法.其核心内容是在尽量减少初始彩色图像失真的前提下,能够将颜色丰富的原始彩色 ...

  9. JavaScript随机生成颜色以及十六进制颜色 与RGB颜色值的相互转换

    /*** 随机生成颜色* @return 随机生成的十六进制颜色 */function randomColor(){var colorStr=Math.floor(Math.random()*0xFF ...

最新文章

  1. LeetCode简单题之最长和谐子序列
  2. 计算机美术与设计方案,试述电脑美术及其在现代设计教学与创作中的作用2200字...
  3. python源码精要(4)-C代码规范
  4. gradle使用技巧之全局变量
  5. curl+个人证书(又叫客户端证书)访问https站点
  6. c2000 汇编语言指令,C2000系CMD文件的配置理解
  7. php 系统交互 删除文件_FileSystemMap:与文件系统交互的自然方法
  8. python excel操作库,可能是全网最完整的 Python 操作 Excel库总结!
  9. debian java7_Debian 7 和 Debian 8 用户怎样安装 Oracle Java 8
  10. php 发送post请求json,thinkphp ,php post发送json请求,就收post请求
  11. vs2013 提交 github
  12. Java中的SoftReference和WeakReference有什么区别?
  13. 排序算法之——堆排序分析
  14. .net Remoting与Web Service的比较
  15. 怎么注册开通个人微信小程序
  16. java udp传输文件6_文件传输udpjava数据
  17. Java使用for循环打印菱形
  18. 一个迅速崛起的国产开源OCR项目!
  19. MySQL 安装 + 入门大全 + 常用命令合集
  20. 麦克劳林公式怎么记忆_怎么背麦克劳林公式?

热门文章

  1. 一图看懂,阿里云飞天企业版如何支持政企数智创新
  2. 3D打印和开源硬件的关系
  3. 论ICT技术与数据中心的关系
  4. 面试英语经典问答 (转)
  5. 计算机清理垃圾文件丢失怎么恢复,垃圾箱清空了怎么恢复
  6. [云炬学英语]每日一句2020.8.30
  7. mysql主从三个线程工作顺序_MySQL主从介绍、准备工作、配置主、配置从、测试主从同步...
  8. Could not find artifact com.dingtalk.api:top-api-sdk-dev:pom:ding-open-mc-SNAPSHOT in aliyunmaven
  9. delphi7 如何加载控件
  10. 怎样在逆光和恶劣光线下拍人像