>>分享数据结构和算法相关的知识和技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 25180 个阅读者 刷新本主题
 * 贴子主题:  图像基本处理算法的简单实现 回复文章 点赞(0)  收藏  
作者:sunshine    发表时间:2020-03-15 17:19:11     消息  查看  搜索  好友  邮件  复制  引用

    图像基本处理算法的简单实现

     一、引言

          图像处理基本算法整理。

         拿来举例的实现代码是在JNI方法内直接实现的,且传入参数为int[]颜色值,返回为新的int[]颜色值,可能头上还包括了长宽。(很丑,见谅T^T)

       二、算法

1)缩放算法

          据说有最邻近插值、双线性内插值、高阶插值、三次卷积法等等。(我已经晕了~)

          缩放是从原图像->目标图像的过程。目标图像的新颜色值,由图像长宽比反向计算在原图像的位置,从而获得。反向计算得到的坐标一般为浮点坐标,表示为(i+u,j+v)(i,j整数整数、u,v小数部分)。

          1)最邻近插值:取(i,j)的颜色值即可,效果不咋的==

          2)双线性内插值:由(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)四点距(i+u,j+v)远近计算比例求得(四领域乘以相应的权重)。效果不错了哈==

公式:f(i+u,j+v)=(1-u)(1-v)*f(i,j)+(1-u)v*f(i,j+1)+u(1-v)*f(i+1,j)+uv*f(i+1,j+1)

复制:双线性内插值具有低通滤波器性质,使高频风量受损,可能会使图像轮廓在一定程度上变得模糊。尤其放大处理,影响将更为明显。

          3)高阶插值、三次卷积法等:说是双线性使细节柔化、会有锯齿什么的。这些算法就是能够更好的修正这些不足,但计算量更大==。(高阶插值没搜索到具体算法啊,是指一类概念么?双三次插值属于高阶插值这类的意思?)

           双线性内插值的实现:

    
  1.    int  min( int  x,  int  y) {
  2.        return  (x <= y) ? x : y;
  3.   }
  4.    int  alpha( int  color) {
  5.        return  (color >> 24) & 0xFF;
  6.   }
  7.    int  red( int  color) {
  8.        return  (color >> 16) & 0xFF;
  9.   }
  10.    int  green( int  color) {
  11.        return  (color >> 8) & 0xFF;
  12.   }
  13.    int  blue( int  color) {
  14.        return  color & 0xFF;
  15.   }
  16.    int  ARGB( int  alpha,  int  red,  int  green,  int  blue) {
  17.        return  (alpha << 24) | (red << 16) | (green << 8) | blue;
  18.   }
  19.    /**
  20.     * 按双线性内插值算法将对应源图像四点颜色某一颜色值混合
  21.     *
  22.     * int(*fun)(int)指向从color中获取某一颜色值的方法
  23.     */  
  24.    int  mixARGB( int  *color,  int  i,  int  j,  float u,  float v,  int (*fun)( int )) {
  25.        // f(i+u,j+v)=(1-u)(1-v)*f(i,j)+(1-u)v*f(i,j+1)+u(1-v)*f(i+1,j)+uv*f(i+1,j+1)  
  26.        return  (1 - u) * (1 - v) * (*fun)(color[0]) + (1 - u) * v * (*fun)(color[1])
  27.               + u * (1 - v) * (*fun)(color[2]) + u * v * (*fun)(color[3]);
  28.   }
  29.    /**
  30.     * 按双线性内插值算法将对应源图像四点颜色值混合
  31.     *
  32.     * color[]需要有四个颜色值,避免越界
  33.     */  
  34.    int  mixColor( int  *color,  int  i,  int  j,  float  u,  float  v) {
  35.        int  a = mixARGB(color, i, j, u, v, alpha);  // 获取alpha混合值  
  36.        int  r = mixARGB(color, i, j, u, v, red);  // 获取red混合值  
  37.        int  g = mixARGB(color, i, j, u, v, green);  // 获取green混合值  
  38.        int  b = mixARGB(color, i, j, u, v, blue);  // 获取blue混合值  
  39.        return  ARGB(a, r, g, b);
  40.   }
  41.    /**
  42.     * 将Bitmap缩放后返回(双线性内插值算法)
  43.     *
  44.     * JNIEnv*  jni环境(jni必要参数)
  45.     * jobject  java对象(jni必要参数)
  46.     * jintArray    Bitmap所有像素值
  47.     * int  Bitmap宽度
  48.     * int  Bitmap高度
  49.     * int  Bitmap新宽度
  50.     * int  Bitmap新高度
  51.     */  
  52.   JNIEXPORT jintArray JNICALL Java_org_join_p_w_picpath_util_JoinImage_stretch(
  53.           JNIEnv* env, jobject obj, jintArray buf,  int  srcW,  int  srcH,  int  dstW,
  54.            int  dstH) {
  55.       LOGE( "==stretch==" );
  56.       jint * cbuf;
  57.       cbuf = (*env)->GetIntArrayElements(env, buf, 0);  // 获取int数组元素  
  58.        int  newSize = dstW * dstH;
  59.       jint rbuf[newSize];  // 新图像像素值  
  60.        float  rateH = ( float ) srcH / dstH;  // 高度缩放比例  
  61.        float  rateW = ( float ) srcW / dstW;  // 宽度缩放比例  
  62.        int  dstX, dstY;  // 目标图像XY坐标  
  63.        float  srcX, srcY;  // 目标图像对应源图像XY坐标  
  64.        int  i, j;  // 对应源图像XY坐标整数部分  
  65.        int  i1, j1;  // 对应源图像XY坐标整数部分+1  
  66.        float  u, v;  // 对应源图像XY坐标小数部分  
  67.        int  color[4];  // f(i+u,j+v)对应源图像(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)的像素值  
  68.        for  (dstY = 0; dstY <= dstH - 1; dstY++) {
  69.           srcY = dstY * rateH;  // 对应源图像Y坐标  
  70.           j = ( int ) srcY;  // 对应源图像Y坐标整数部分  
  71.           j1 = min(j + 1, srcH - 1);  // 对应源图像Y坐标整数部分+1  
  72.           v = srcY - j;  // 对应源图像Y坐标小数部分  
  73.            for  (dstX = 0; dstX <= dstW - 1; dstX++) {
  74.               srcX = dstX * rateW;  // 对应源图像X坐标  
  75.               i = ( int ) srcX;  // 对应源图像X坐标整数部分  
  76.               i1 = min(i + 1, srcW - 1);  // 对应源图像X坐标整数部分+1  
  77.               u = srcX - i;  // 对应源图像X坐标小数部分  
  78.                // 双线性内插值算法(注意ARGB时,需要分别由插值算法求得后重组):  
  79.                // f(i+u,j+v)=(1-u)(1-v)*f(i,j)+(1-u)v*f(i,j+1)+u(1-v)*f(i+1,j)+uv*f(i+1,j+1)  
  80.               color[0] = cbuf[j * srcW + i];  // f(i,j)颜色值  
  81.               color[1] = cbuf[j1 * srcW + i];  // f(i,j+1)颜色值  
  82.               color[2] = cbuf[j * srcW + i1];  // f(i+1,j)颜色值  
  83.               color[3] = cbuf[j1 * srcW + i1];  // f(i+1,j+1)颜色值  
  84.                // 给目标图像赋值为双线性内插值求得的混合色  
  85.               rbuf[dstY * dstW + dstX] = mixColor(color, i, j, u, v);
  86.           }
  87.       }
  88.       jintArray result = (*env)->NewIntArray(env, newSize);  // 新建一个jintArray  
  89.       (*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);  // 将rbuf转存入result  
  90.       (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);  // 释放int数组元素  
  91.        return  result;
  92.   }

           2)灰度化

          把图像变灰,有好些方法,求RGB平均值啊,RGB最大值啊什么的。不过还是建议按规范的标准来。

          彩色转灰度的著名心理学公式:Gray = R*0.299 + G*0.587 + B*0.114(话说我心理学与生活一本书都看完了也没提到这公式啊==)

          实际应用中为了避免浮点运算,然后就有了移位运算代替了。

           2至20位精度的系数:

  1.    Gray = (R*1 + G*2 + B*1) >> 2
  2.   Gray = (R*2 + G*5 + B*1) >> 3
  3.   Gray = (R*4 + G*10 + B*2) >> 4
  4.   Gray = (R*9 + G*19 + B*4) >> 5
  5.   Gray = (R*19 + G*37 + B*8) >> 6
  6.   Gray = (R*38 + G*75 + B*15) >> 7
  7.   Gray = (R*76 + G*150 + B*30) >> 8
  8.   Gray = (R*153 + G*300 + B*59) >> 9
  9.   Gray = (R*306 + G*601 + B*117) >> 10
  10.   Gray = (R*612 + G*1202 + B*234) >> 11
  11.   Gray = (R*1224 + G*2405 + B*467) >> 12
  12.   Gray = (R*2449 + G*4809 + B*934) >> 13
  13.   Gray = (R*4898 + G*9618 + B*1868) >> 14
  14.   Gray = (R*9797 + G*19235 + B*3736) >> 15
  15.   Gray = (R*19595 + G*38469 + B*7472) >> 16
  16.   Gray = (R*39190 + G*76939 + B*14943) >> 17
  17.   Gray = (R*78381 + G*153878 + B*29885) >> 18
  18.   Gray = (R*156762 + G*307757 + B*59769) >> 19
  19.   Gray = (R*313524 + G*615514 + B*119538) >> 20

                    3与4、7与8、10与11、13与14、19与20的精度说是一样的==。16位运算下最好的计算公式是使用7位精度。而游戏由于场景经常变化,用户感觉不到,最常用2位精度。

           灰度化实现:

  1.    JNIEXPORT jintArray JNICALL Java_org_join_p_w_picpath_util_JoinImage_imgToGray(
  2.           JNIEnv* env, jobject obj, jintArray buf,  int  w,  int  h) {
  3.       LOGE( "==imgToGray==" );
  4.       jint * cbuf;
  5.       cbuf = (*env)->GetIntArrayElements(env, buf, 0);  // 获取int数组元素  
  6.        int  alpha = 0xFF;  // 不透明值  
  7.        int  i, j, color, red, green, blue;
  8.        for  (i = 0; i < h; i++) {
  9.            for  (j = 0; j < w; j++) {
  10.               color = cbuf[w * i + j];  // 获得color值  
  11.               red = (color >> 16) & 0xFF;  // 获得red值  
  12.               green = (color >> 8) & 0xFF;  // 获得green值  
  13.               blue = color & 0xFF;  // 获得blue值  
  14.               color = (red * 38 + green * 75 + blue * 15) >> 7;  // 灰度算法(16位运算下7位精度)  
  15.               color = (alpha << 24) | (color << 16) | (color << 8) | color;  // 由ARGB组成新的color值  
  16.               cbuf[w * i + j] = color;  // 设置新color值  
  17.           }
  18.       }
  19.        int  size = w * h;
  20.       jintArray result = (*env)->NewIntArray(env, size);  // 新建一个jintArray  
  21.       (*env)->SetIntArrayRegion(env, result, 0, size, cbuf);  // 将cbuf转存入result  
  22.       (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);  // 释放int数组元素  
  23.        return  result;
  24.   }

           3)二值化

          灰度值[0,255]和一阈值比较,变成0或255,要么纯黑要么纯白==。但是阈值的获取就牵扯算法了。只知道有Otsu、Bernsen…,具体算法查下就好^^

          Otsu:最大类间方差法,整体算出一个阈值。计算次数少但抗干扰性差,适合光照均匀的图像。

          Bernsen:局部阈值法,在一点周围一定范围内(相当于一窗口)计算出一阈值。计算次数多但抗干扰性强,用于非均匀光照的图像。

           二值化(Otsu)的实现:

  1.    /**
  2.     * 将灰度化Bitmap各像素值二值化后返回
  3.     *
  4.     * JNIEnv*  jni环境(jni必要参数)
  5.     * jobject  java对象(jni必要参数)
  6.     * jintArray    Bitmap所有像素值
  7.     * int  Bitmap宽度
  8.     * int  Bitmap高度
  9.     */  
  10.   JNIEXPORT jintArray JNICALL Java_org_join_p_w_picpath_util_JoinImage_binarization(
  11.           JNIEnv* env, jobject obj, jintArray buf,  int  w,  int  h) {
  12.       LOGE( "==binarization==" );
  13.       jint * cbuf;
  14.       cbuf = (*env)->GetIntArrayElements(env, buf, 0);  // 获取int数组元素  
  15.        int  white = 0xFFFFFFFF;  // 不透明白色  
  16.        int  black = 0xFF000000;  // 不透明黑色  
  17.        int  thresh = otsu(cbuf, w, h);  // OTSU获取分割阀值  
  18.       LOGE( "==[阀值=%d]==" , thresh);
  19.        int  i, j, gray;
  20.        for  (i = 0; i < h; i++) {
  21.            for  (j = 0; j < w; j++) {
  22.               gray = (cbuf[w * i + j]) & 0xFF;  // 获得灰度值(red=green=blue)  
  23.                if  (gray < thresh) {
  24.                   cbuf[w * i + j] = white;  // 小于阀值设置为白色(前景)  
  25.               }  else  {
  26.                   cbuf[w * i + j] = black;  // 否则设置为黑色(背景)  
  27.               }
  28.           }
  29.       }
  30.        int  size = w * h;
  31.       jintArray result = (*env)->NewIntArray(env, size);  // 新建一个jintArray  
  32.       (*env)->SetIntArrayRegion(env, result, 0, size, cbuf);  // 将cbuf转存入result  
  33.       (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);  // 释放int数组元素  
  34.        return  result;
  35.   }
  36.    /**
  37.     * OTSU算法求最适分割阈值
  38.     */  
  39.    int  otsu(jint* colors,  int  w,  int  h) {
  40.       unsigned  int  pixelNum[256];  // 图象灰度直方图[0, 255]  
  41.        int  color;  // 灰度值  
  42.        int  n, n0, n1;  //  图像总点数,前景点数, 后景点数(n0 + n1 = n)  
  43.        int  w0, w1;  // 前景所占比例, 后景所占比例(w0 = n0 / n, w0 + w1 = 1)  
  44.        double  u, u0, u1;  // 总平均灰度,前景平均灰度,后景平均灰度(u = w0 * u0 + w1 * u1)  
  45.        double  g, gMax;  // 图像类间方差,最大类间方差(g = w0*(u0-u)^2+w1*(u1-u)^2 = w0*w1*(u0-u1)^2)  
  46.        double  sum_u, sum_u0, sum_u1;  // 图像灰度总和,前景灰度总和, 后景平均总和(sum_u = n * u)  
  47.        int  thresh;  // 阈值  
  48.       memset(pixelNum, 0, 256 *  sizeof (unsigned  int ));  // 数组置0  
  49.        // 统计各灰度数目  
  50.        int  i, j;
  51.        for  (i = 0; i < h; i++) {
  52.            for  (j = 0; j < w; j++) {
  53.               color = (colors[w * i + j]) & 0xFF;  // 获得灰度值  
  54.               pixelNum[color]++;  // 相应灰度数目加1  
  55.           }
  56.       }
  57.        // 图像总点数  
  58.       n = w * h;
  59.        // 计算总灰度  
  60.        int  k;
  61.        for  (k = 0; k <= 255; k++) {
  62.           sum_u += k * pixelNum[k];
  63.       }
  64.        // 遍历判断最大类间方差,得到最佳阈值  
  65.        for  (k = 0; k <= 255; k++) {
  66.           n0 += pixelNum[k];  // 图像前景点数  
  67.            if  (0 == n0) {  // 未获取前景,直接继续增加前景点数  
  68.                continue ;
  69.           }
  70.            if  (n == n0) {  // 前景点数包括了全部时,不可能再增加,退出循环  
  71.                break ;
  72.           }
  73.           n1 = n - n0;  // 图像后景点数  
  74.           sum_u0 += k * pixelNum[k];  // 前景灰度总和  
  75.           u0 = sum_u0 / n0;  // 前景平均灰度  
  76.           u1 = (sum_u - sum_u0) / n1;  // 后景平均灰度  
  77.           g = n0 * n1 * (u0 - u1) * (u0 - u1);  // 类间方差(少除了n^2)  
  78.            if  (g > gMax) {  // 大于最大类间方差时  
  79.               gMax = g;  // 设置最大类间方差  
  80.               thresh = k;  // 取最大类间方差时对应的灰度的k就是最佳阈值  
  81.           }
  82.       }
  83.        return  thresh;
  84.   }

----------------------------
原文链接:https://blog.51cto.com/vaero/822997

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 sunweiqin 在 2020-03-15 17:19:11 重新编辑]
  Java面向对象编程-->图形用户界面(上)
  JavaWeb开发-->使用Session(Ⅰ)
  JSP与Hibernate开发-->Java对象持久化技术概述
  Java网络编程-->XML数据处理
  精通Spring-->CSS过渡和动画
  Vue3开发-->Vue组件开发高级技术
  整理得吐血了,二叉树、红黑树、B、B+树超齐全,快速搞定数据...
  算法学习与收集:一些有用的算法网站和网页
  深度学习之图片压缩算法
  Java 选择排序算法
  如何面对“算法”的困惑?
  基于SQL的数据库算法研究
  令牌桶算法
  活动安排问题(贪心算法)
  用Java实现回文数算法
  Java算法题:有关100阶楼梯的算法
  微软面试题:买卖股票的最佳时机
  字节跳动面试官这样问消息队列:分布式事务、重复消费、顺序...
  小米面试算法题:搜索旋转排序数组
  RSA算法的数学原理
  浅谈常见的七种加密算法及实现
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。