<span style="font-size:48px;color:#cc66cc;">ColorReduce</span>
<span style="font-size:48px;color:#cc66cc;">ColorReduce</span>
void colorReduce(cv::Mat image, int div)
彩色图像由三个通道像素组成(RGB),因此颜色总数为256*256*256。为了降低分析的复杂性,可以通过colorReduce函数把每种颜色数量减少8倍,则颜色总数变成32*32*32。因此基本的减色算法很简单,假设N是减色因子,则代码实现就是简单的value/N*N,可以得到N的倍数,并且刚好不超过原始像素值。只需加上N/2就得到相邻的N倍数之间的中间值。最后对所有8位通道值重复这个过程,就会得到(256/N)*(256/N)*(256/N)种可能的颜色值。
(a)原始图像 (b)ColorReduce64倍
方法一:.ptr和数组操作
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Times New Roman;font-size:18px;">void colorReduce1(cv::Mat &image, int div = 64) { //64是减色因子
int nl = image.rows; // number of lines
int nc = image.cols * image.channels(); // total number of elements per line
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);//访问图像中一个行地址就用.ptr
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
data[i] = data[i] / div*div + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span></span>
方法二:.ptr和指针操作*++
<span style="font-family:Times New Roman;font-size:18px;">void colorReduce2(cv::Mat &image, int div = 64) {
int nl = image.rows; // number of lines
int nc = image.cols * image.channels(); // total number of elements per line
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
*data++ = *data / div*div + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span>
方法三:.ptr,指针操作*++和位运算
<span style="font-family:Times New Roman;font-size:18px;">void colorReduce3(cv::Mat &image, int div = 64) {
int nl = image.rows; // number of lines
int nc = image.cols * image.channels(); // total number of elements per line
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
// mask used to round the pixel value
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
*data++ = *data&mask + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span>
方法四:Mat迭代器
<span style="font-family:Times New Roman;font-size:18px;">void colorReduce4(cv::Mat &image, int div = 64) {
// get iterators
cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
for (; it != itend; ++it) {
// process each pixel ---------------------
(*it)[0] = (*it)[0] / div*div + div / 2;
(*it)[1] = (*it)[1] / div*div + div / 2;
(*it)[2] = (*it)[2] / div*div + div / 2;
// end of pixel processing ----------------
}
}</span>
方法五:.at 图像坐标<span style="font-family:Times New Roman;font-size:18px;font-weight: normal;">void colorReduce5(cv::Mat &image, int div = 64) {
int nl = image.rows; // number of lines
int nc = image.cols; // number of columns
for (int j = 0; j<nl; j++) {
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
image.at<cv::Vec3b>(j, i)[0] = image.at<cv::Vec3b>(j, i)[0] / div*div + div / 2;
image.at<cv::Vec3b>(j, i)[1] = image.at<cv::Vec3b>(j, i)[1] / div*div + div / 2;
image.at<cv::Vec3b>(j, i)[2] = image.at<cv::Vec3b>(j, i)[2] / div*div + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span>
<span style="font-family:Times New Roman;font-size:18px;font-weight: normal;">void colorReduce5(cv::Mat &image, int div = 64) {
int nl = image.rows; // number of lines
int nc = image.cols; // number of columns
for (int j = 0; j<nl; j++) {
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
image.at<cv::Vec3b>(j, i)[0] = image.at<cv::Vec3b>(j, i)[0] / div*div + div / 2;
image.at<cv::Vec3b>(j, i)[1] = image.at<cv::Vec3b>(j, i)[1] / div*div + div / 2;
image.at<cv::Vec3b>(j, i)[2] = image.at<cv::Vec3b>(j, i)[2] / div*div + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span>
方法六:创建输出图像
<pre name="code" class="cpp"><span style="font-family:Times New Roman;font-size:18px;font-weight: normal;">void colorReduce6(const cv::Mat &image, // input image
cv::Mat &result, // output image
int div = 64) {
int nl = image.rows; // number of lines
int nc = image.cols; // number of columns
// allocate output image if necessary
result.create(image.rows, image.cols, image.type());
// created images have no padded pixels
nc = nc*nl;
nl = 1; // it is now a 1D array
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
// mask used to round the pixel value
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
for (int j = 0; j<nl; j++) {
uchar* data = result.ptr<uchar>(j);
const uchar* idata = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++) {
// process each pixel ---------------------
*data++ = (*idata++)&mask + div / 2;
*data++ = (*idata++)&mask + div / 2;
*data++ = (*idata++)&mask + div / 2;
// end of pixel processing ----------------
} // end of line
}
}</span>
方法七:重载操作
<span style="font-family:Times New Roman;font-size:18px;font-weight: normal;">void colorReduce7(cv::Mat &image, int div = 64) {
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
// mask used to round the pixel value
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
// perform color reduction
image = (image&cv::Scalar(mask, mask, mask)) + cv::Scalar(div / 2, div / 2, div / 2);
}</span>