Android中OpenCV实现图片 浮雕,马赛克,毛玻璃 ,油画效果

这篇我们利用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);
}
浮雕.jpg

马赛克:
马赛克效果就是把图片分成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);
}
马赛克.png

毛玻璃:
毛玻璃效果和马赛克比较相近,下面代码实现是把图片分割成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);


}
毛玻璃.png

油画效果:
是通过像素权重实现图像的像素模糊从而达到近似油画效果模糊,(直方统计)
具体的
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);


}
油画效果.jpg
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容