减色算法

彩色图像由三通道组成,用8位无符号整型表示时颜色总数为 256256256=16777216 256 ∗ 256 ∗ 256 = 16777216 种,非常巨大,有时为了降低分析的复杂性会做减少颜色数量的处理。

Method1—利用整数除法特性

一种处理方法是将RGB空间细分到大小相等的方块中。例如,如果把每种颜色数量减少到1/8,那么颜色总数就变为 323232 32 ∗ 32 ∗ 32 。将原图像中每个颜色值划分到一个方块,该方块的中间值就是新的颜色值;新图像使用新的颜色值,颜色数就变少了。
具体地,假设N是减色因子,将图像中每个像素的值除以 N N (使用整数除法,不保留余数。实际上,该算法就是利用了整数除法的特性来实现减色的)。然后将结果乘以N,得到 N N 的倍数,再加上N/2,就得到相邻的 N N 的倍数之间的中间值。对所有8位通道值重复这个过程,就会得到(256/N)(256/N)(256/N)种可能的颜色值。
实现方法如下,
减色函数:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

/* 假设输入输出都是三通道图像,如果是灰度图处理方法类似 */
/* 首先检查输出图像宽、高、数据类型是否与输入一致,
   如果一致则使用原始输出图像,否则创建新的输出图像*/
void colorReduce(const cv::Mat &image, cv::Mat &result, int div=64)
{
    /* 在调用create时会自动检查要求创建的宽、高、数据类型是否与result匹配,
       如果匹配则create不会创建新的Mat直接使用result,否则会创建新的Mat赋给result*/
    result.create(cv::Size(image.cols, image.rows), image.type());
    for (int i = 0; i != image.rows; ++i)
    {
        const cv::Vec3b * const ptr_image = image.ptr<cv::Vec3b>(i);
        cv::Vec3b * ptr_result = result.ptr<cv::Vec3b>(i);
        /* 利用整数除法特性进行减色 */
        for (int j = 0; j != image.cols; ++j)
        {
            ptr_result[j] = ptr_image[j] / div*div + cv::Vec3b(div/2, div/2, div/2);
        }
    }
}

使用demo:

int main()
{
    cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
    cv::resize(img, img, cv::Size(img.cols, img.rows));
    cv::imshow("img", img);
    /* colorReduce()中create()会创建新的Mat赋给result */
    cv::Mat result;
#if 0
    /* colorReduce()中create()不会创建新的Mat而是直接使用result */
    cv::Mat result(img.rows, img.cols, img.type());
#endif

    /* 调用减色函数 */
    colorReduce(img, result,128);

    cv::imshow("result", result);
    cv::waitKey(0);
}

效果如图1所示:

ellipse
图1 整数除法特性实现减色
Method2—取模运算

使用取模运算符实现减色算法。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

/* 假设输入输出都是三通道图像,如果是灰度图处理方法类似 */
/* 首先检查输出图像宽、高、数据类型是否与输入一致,
   如果一致则使用原始输出图像,否则创建新的输出图像*/
void colorReduce(const cv::Mat &image, cv::Mat &result, int div=64)
{
    /* 在调用create时会自动检查要求创建的宽、高、数据类型是否与result匹配,
       如果匹配则create不会创建新的Mat直接使用result,否则会创建新的Mat赋给result*/
    result.create(cv::Size(image.cols, image.rows), image.type());
    for (int i = 0; i != image.rows; ++i)
    {
        const cv::Vec3b * const ptr_image = image.ptr<cv::Vec3b>(i);
        cv::Vec3b * ptr_result = result.ptr<cv::Vec3b>(i);
        /* 利用取模运算符进行减色 */
        for (int j = 0; j != image.cols; ++j)
        {
            ptr_result[j][0] = ptr_image[j][0] - ptr_image[j][0] % div + div / 2;
            ptr_result[j][1] = ptr_image[j][1] - ptr_image[j][1] % div + div / 2;
            ptr_result[j][2] = ptr_image[j][2] - ptr_image[j][2] % div + div / 2;
        }
    }
}

int main()
{
    cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
    cv::resize(img, img, cv::Size(img.cols, img.rows));
    cv::imshow("img", img);
    /* colorReduce()中create()会创建新的Mat赋给result */
    cv::Mat result;
#if 0
    /* colorReduce()中create()不会创建新的Mat而是直接使用result */
    cv::Mat result(img.rows, img.cols, img.type());
#endif

    /* 调用减色函数 */
    colorReduce(img, result,128);

    cv::imshow("result", result);
    cv::waitKey(0);
}

效果如图2所示:

ellipse
图2 取模运算实现减色
Method3—位运算符实现减色算法

如果把减色因子限定为2的指数,即 div=pow(2,n) d i v = p o w ( 2 , n ) ,那么把像素值的前n位掩码后就能得到最接近的div的倍数,可以用简单的移位操作获得掩码。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

/* 假设输入输出都是三通道图像,如果是灰度图处理方法类似 */
/* 首先检查输出图像宽、高、数据类型是否与输入一致,
如果一致则使用原始输出图像,否则创建新的输出图像*/
void colorReduce(const cv::Mat &image, cv::Mat &result, int n = 6)//div=pow(2,n)=128
{
    cv::Vec3b mask(0xFF << n, 0xFF << n, 0xFF << n);
    /* 在调用create时会自动检查要求创建的宽、高、数据类型是否与result匹配,
    如果匹配则create不会创建新的Mat直接使用result,否则会创建新的Mat赋给result*/
    result.create(cv::Size(image.cols, image.rows), image.type());
    for (int i = 0; i != image.rows; ++i)
    {
        const cv::Vec3b * const ptr_image = image.ptr<cv::Vec3b>(i);
        cv::Vec3b * ptr_result = result.ptr<cv::Vec3b>(i);
        for (int j = 0; j != image.cols; ++j)
        {
            /* 利用位运算符实现减色 */
            ptr_result[j][0] = ptr_image[j][0] & mask[0]; ptr_result[j][0] += pow(2,n)/2;
            ptr_result[j][1] = ptr_image[j][1] & mask[1]; ptr_result[j][1] += pow(2,n)/2;
            ptr_result[j][2] = ptr_image[j][2] & mask[2]; ptr_result[j][2] += pow(2,n)/2;
        }
    }
}
int main()
{
    cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
    cv::resize(img, img, cv::Size(img.cols, img.rows));
    cv::imshow("img", img);
    /* colorReduce()中create()会创建新的Mat赋给result */
    cv::Mat result;
#if 0
    /* colorReduce()中create()不会创建新的Mat而是直接使用result */
    cv::Mat result(img.rows, img.cols, img.type());
#endif

    /* 调用减色函数 */
    colorReduce(img, result,7);

    cv::imshow("result", result);
    cv::waitKey(0);
}

效果如图3所示:

ellipse
图3 移位操作实现减色
参考文献

OpenCV Tutorials
Robert Laganiere著、相银初译. OpenCV 3 Computer Vision, Application Programming Cookbook, Third Edition[D]. 人民邮电出版社, 2018.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值