这篇我们利用Opencv 实现 浮雕,马赛克,毛玻璃一些简单的效果,因为在Android 实现我们要将Bitmap转Mat给opencv进行操作,opencv操作完图片又要将Mat转化成Bitmap,上篇文章已经讲到Bitmap与Mat的相互转化https://www.jianshu.com/p/c57ee524ad52,在我们实现这些效果的时候其实是对图片的没一个像素点进行操作,接下来我们来看看具体的效果。
浮雕:
浮雕的算法是对图像的每一个点进行卷积处理,采用的矩阵如下
[1 0 0;
0 0 0;
0 0 -1 ];
假设原图src 处理后图像outImg 对于坐标为(row,col)点,其浮雕表达方程式 outImg(row,col) = src (row-1,col-1)-src (row+1,col+1)+128;
还可以用下面这种算子
[1 0
0 -1]
假设原图src 处理后图像outImg 对于坐标为(row,col)点,其浮雕表达方程式 outImg(row,col) = src (row,col)-src (row+1,col+1)+128;
下面代码是用第二种算子实现的浮雕
/**
* 浮雕
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_opencv_BitmapUtils_relief(JNIEnv *env, jclass type, jobject bitmap) {
Mat src;
bitmap2Mat(env, src, bitmap);
/**
* [1,0]
* [0,-1]
*/
Mat relief(src.size(), src.type());
for (int row = 1; row < src.rows; ++row) {
for (int col = 1; col < src.cols; ++col) {
Vec4b pix_p = src.at<Vec4b>(row - 1, col - 1);
Vec4b pix_n = src.at<Vec4b>(row, col);
//b g r a
relief.at<Vec4b>(row, col)[0] = static_cast<uchar>(pix_p[0] - pix_n[0] + 128);
relief.at<Vec4b>(row, col)[1] = static_cast<uchar>(pix_p[1] - pix_n[1] + 128);
relief.at<Vec4b>(row, col)[2] = static_cast<uchar>(pix_p[2] - pix_n[2] + 128);
}
}
mat2Bitmap(env, relief, bitmap);
}
马赛克:
马赛克效果就是把图片分成n*n的小块 n 的取值要适中,下面代码实现是将图片分成很多个8x8的若干个小块,取小块中的第一个点的像素值来填充这个小块来达到马赛克的效果
/**
* 马赛克
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_opencv_BitmapUtils_mosaic(JNIEnv *env, jclass type, jobject bitmap) {
Mat src;
bitmap2Mat(env, src, bitmap);
int size = 8; //分成8 * 8 的小块 填充相同的颜色
Mat mosaic= src.clone();
for (int row = 0; row < src.rows - size; row += size) {
for (int col = 0; col < src.cols - size; col += size) {
Vec4b src_pix = src.at<Vec4b>(row, col);
for (int row_i = 0; row_i < size; ++row_i) {
for (int col_i = 0; col_i < size; ++col_i) {
mosaic.at<Vec4b>(row + row_i, col + col_i) = src_pix;
}
}
}
}
mat2Bitmap(env, mosaic, bitmap);
}
毛玻璃:
毛玻璃效果和马赛克比较相近,下面代码实现是把图片分割成5x5的若干个小块,在小块中取随机点的像素值来填充小块中的点。
/**
* 毛玻璃效果
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_opencv_BitmapUtils_frostedGlass(JNIEnv *env, jclass type, jobject bitmap) {
Mat src;
bitmap2Mat(env, src, bitmap);
int size = 5; //分成5 * 5的小块 在小块中随机取值填充
Mat frostedGlass = src.clone();
RNG rng((unsigned) time(NULL));
for (int row = 0; row < src.rows - size; ++row) {
for (int col = 0; col < src.cols - size; ++col) {
int roandnumber = rng.uniform(0, size);
frostedGlass.at<Vec4b>(row, col)[0] = src.at<Vec4b>(row + roandnumber, col + roandnumber)[0];
frostedGlass.at<Vec4b>(row, col)[1] = src.at<Vec4b>(row + roandnumber, col + roandnumber)[1];
frostedGlass.at<Vec4b>(row, col)[2] = src.at<Vec4b>(row + roandnumber, col + roandnumber)[2];
}
}
mat2Bitmap(env, frostedGlass, bitmap);
}
油画效果:
是通过像素权重实现图像的像素模糊从而达到近似油画效果模糊,(直方统计)
具体的
1.把(0~255)灰度值均分成n个区间
2.遍历图像的每个像素点 将模板范围内的所有像素值进一步离散化,根据像素的灰度落入不同的区间,
3.找到落入像素最多的一个区间 并桶对该区间中的所有像素求出颜色平均值 作为位置 (x, y) 的结果值
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_opencv_BitmapUtils_oilPaintI(JNIEnv *env, jclass type, jobject bitmap) {
Mat src;
bitmap2Mat(env, src, bitmap);
Mat gray;
cvtColor(src, gray, COLOR_BGRA2GRAY);
Mat res = src.clone();
const int g_size = 5;
const int t_size = 8;
for (int row = 0; row < src.rows - t_size; ++row) {
for (int col = 0; col < src.cols - t_size; ++col) {
//统计灰度等级
int grade[g_size + 1] = {0};
int b[g_size + 1] = {0};
int g[g_size + 1] = {0};
int r[g_size + 1] = {0};
for (int t_row = 0; t_row < t_size; ++t_row) {
for (int t_col = 0; t_col < t_size; ++t_col) {
uchar gray_value = gray.at<uchar>(row + t_row, col + t_col);
int grade_index = gray_value / (255 / g_size);
grade[grade_index] += 1;
b[grade_index] += src.at<Vec4b>(row + t_row, col + t_col)[0];
g[grade_index] += src.at<Vec4b>(row + t_row, col + t_col)[1];
r[grade_index] += src.at<Vec4b>(row + t_row, col + t_col)[2];
}
}
//找出最多落入像素最多的一个等级
int max_index = 0;
int max = grade[0];
for (int index = 1; index <= g_size; ++index) {
if (grade[index] > max) {
max_index = index;
max = grade[index];
}
}
//求取这个等级的平均值
res.at<Vec4b>(row, col)[0] = b[max_index] / max;
res.at<Vec4b>(row, col)[1] = g[max_index] / max;
res.at<Vec4b>(row, col)[2] = r[max_index] / max;
}
}
mat2Bitmap(env, res, bitmap);
}