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

简介:

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

一、引言
         图像处理基本算法整理。
 
         拿来举例的实现代码是在JNI方法内直接实现的,且传入参数为int[]颜色值,返回为新的int[]颜色值,可能头上还包括了长宽。(很丑,见谅T^T)
 
         2.2的NDK提供了Bitmap.h,这种方式可参考《 Android NDK基础样例》的样例3,灰度化图像(Bitmap作为参数)。
 
二、目录
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. int alpha(int color) { 
  4.     return (color >> 24) & 0xFF; 
  5. int red(int color) { 
  6.     return (color >> 16) & 0xFF; 
  7. int green(int color) { 
  8.     return (color >> 8) & 0xFF; 
  9. int blue(int color) { 
  10.     return color & 0xFF; 
  11. int ARGB(int alpha, int red, int green, int blue) { 
  12.     return (alpha << 24) | (red << 16) | (green << 8) | blue; 
  13.  
  14. /** 
  15.  * 按双线性内插值算法将对应源图像四点颜色某一颜色值混合 
  16.  * 
  17.  * int(*fun)(int)指向从color中获取某一颜色值的方法 
  18.  */ 
  19. int mixARGB(int *color, int i, int j, float u, float v, int(*fun)(int)) { 
  20.     // 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) 
  21.     return (1 - u) * (1 - v) * (*fun)(color[0]) + (1 - u) * v * (*fun)(color[1]) 
  22.             + u * (1 - v) * (*fun)(color[2]) + u * v * (*fun)(color[3]); 
  23.  
  24. /** 
  25.  * 按双线性内插值算法将对应源图像四点颜色值混合 
  26.  * 
  27.  * color[]需要有四个颜色值,避免越界 
  28.  */ 
  29. int mixColor(int *color, int i, int j, float u, float v) { 
  30.     int a = mixARGB(color, i, j, u, v, alpha); // 获取alpha混合值 
  31.     int r = mixARGB(color, i, j, u, v, red); // 获取red混合值 
  32.     int g = mixARGB(color, i, j, u, v, green); // 获取green混合值 
  33.     int b = mixARGB(color, i, j, u, v, blue); // 获取blue混合值 
  34.     return ARGB(a, r, g, b); 
  35.  
  36. /** 
  37.  * 将Bitmap缩放后返回(双线性内插值算法) 
  38.  * 
  39.  * JNIEnv*  jni环境(jni必要参数) 
  40.  * jobject  java对象(jni必要参数) 
  41.  * jintArray    Bitmap所有像素值 
  42.  * int  Bitmap宽度 
  43.  * int  Bitmap高度 
  44.  * int  Bitmap新宽度 
  45.  * int  Bitmap新高度 
  46.  */ 
  47. JNIEXPORT jintArray JNICALL Java_org_join_image_util_JoinImage_stretch( 
  48.         JNIEnv* env, jobject obj, jintArray buf, int srcW, int srcH, int dstW, 
  49.         int dstH) { 
  50.     LOGE("==stretch=="); 
  51.  
  52.     jint * cbuf; 
  53.     cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
  54.  
  55.     int newSize = dstW * dstH; 
  56.     jint rbuf[newSize]; // 新图像像素值 
  57.  
  58.     float rateH = (float) srcH / dstH; // 高度缩放比例 
  59.     float rateW = (float) srcW / dstW; // 宽度缩放比例 
  60.  
  61.     int dstX, dstY; // 目标图像XY坐标 
  62.     float srcX, srcY; // 目标图像对应源图像XY坐标 
  63.     int i, j; // 对应源图像XY坐标整数部分 
  64.     int i1, j1; // 对应源图像XY坐标整数部分+1 
  65.     float u, v; // 对应源图像XY坐标小数部分 
  66.     int color[4]; // f(i+u,j+v)对应源图像(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)的像素值 
  67.  
  68.     for (dstY = 0; dstY <= dstH - 1; dstY++) { 
  69.  
  70.         srcY = dstY * rateH; // 对应源图像Y坐标 
  71.         j = (int) srcY; // 对应源图像Y坐标整数部分 
  72.         j1 = min(j + 1, srcH - 1); // 对应源图像Y坐标整数部分+1 
  73.         v = srcY - j; // 对应源图像Y坐标小数部分 
  74.  
  75.         for (dstX = 0; dstX <= dstW - 1; dstX++) { 
  76.  
  77.             srcX = dstX * rateW; // 对应源图像X坐标 
  78.             i = (int) srcX; // 对应源图像X坐标整数部分 
  79.             i1 = min(i + 1, srcW - 1); // 对应源图像X坐标整数部分+1 
  80.             u = srcX - i; // 对应源图像X坐标小数部分 
  81.  
  82.             // 双线性内插值算法(注意ARGB时,需要分别由插值算法求得后重组): 
  83.             // 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) 
  84.             color[0] = cbuf[j * srcW + i]; // f(i,j)颜色值 
  85.             color[1] = cbuf[j1 * srcW + i]; // f(i,j+1)颜色值 
  86.             color[2] = cbuf[j * srcW + i1]; // f(i+1,j)颜色值 
  87.             color[3] = cbuf[j1 * srcW + i1]; // f(i+1,j+1)颜色值 
  88.  
  89.             // 给目标图像赋值为双线性内插值求得的混合色 
  90.             rbuf[dstY * dstW + dstX] = mixColor(color, i, j, u, v); 
  91.         } 
  92.     } 
  93.  
  94.     jintArray result = (*env)->NewIntArray(env, newSize); // 新建一个jintArray 
  95.     (*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf); // 将rbuf转存入result 
  96.     (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
  97.     return result; 
 
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_image_util_JoinImage_imgToGray( 
  2.         JNIEnv* env, jobject obj, jintArray buf, int w, int h) { 
  3.     LOGE("==imgToGray=="); 
  4.  
  5.     jint * cbuf; 
  6.     cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
  7.  
  8.     int alpha = 0xFF; // 不透明值 
  9.     int i, j, color, red, green, blue; 
  10.     for (i = 0; i < h; i++) { 
  11.         for (j = 0; j < w; j++) { 
  12.             color = cbuf[w * i + j]; // 获得color值 
  13.             red = (color >> 16) & 0xFF; // 获得red值 
  14.             green = (color >> 8) & 0xFF; // 获得green值 
  15.             blue = color & 0xFF; // 获得blue值 
  16.             color = (red * 38 + green * 75 + blue * 15) >> 7; // 灰度算法(16位运算下7位精度) 
  17.             color = (alpha << 24) | (color << 16) | (color << 8) | color; // 由ARGB组成新的color值 
  18.             cbuf[w * i + j] = color; // 设置新color值 
  19.         } 
  20.     } 
  21.  
  22.     int size = w * h; 
  23.     jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
  24.     (*env)->SetIntArrayRegion(env, result, 0, size, cbuf); // 将cbuf转存入result 
  25.     (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
  26.     return result; 
 
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_image_util_JoinImage_binarization( 
  11.         JNIEnv* env, jobject obj, jintArray buf, int w, int h) { 
  12.     LOGE("==binarization=="); 
  13.  
  14.     jint * cbuf; 
  15.     cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
  16.  
  17.     int white = 0xFFFFFFFF; // 不透明白色 
  18.     int black = 0xFF000000; // 不透明黑色 
  19.     int thresh = otsu(cbuf, w, h); // OTSU获取分割阀值 
  20.  
  21.     LOGE("==[阀值=%d]==", thresh); 
  22.  
  23.     int i, j, gray; 
  24.     for (i = 0; i < h; i++) { 
  25.         for (j = 0; j < w; j++) { 
  26.             gray = (cbuf[w * i + j]) & 0xFF; // 获得灰度值(red=green=blue) 
  27.             if (gray < thresh) { 
  28.                 cbuf[w * i + j] = white; // 小于阀值设置为白色(前景) 
  29.             } else { 
  30.                 cbuf[w * i + j] = black; // 否则设置为黑色(背景) 
  31.             } 
  32.         } 
  33.     } 
  34.  
  35.     int size = w * h; 
  36.     jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
  37.     (*env)->SetIntArrayRegion(env, result, 0, size, cbuf); // 将cbuf转存入result 
  38.     (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
  39.     return result; 
  40.  
  41. /** 
  42.  * OTSU算法求最适分割阈值 
  43.  */ 
  44. int otsu(jint* colors, int w, int h) { 
  45.     unsigned int pixelNum[256]; // 图象灰度直方图[0, 255] 
  46.     int color; // 灰度值 
  47.     int n, n0, n1; //  图像总点数,前景点数, 后景点数(n0 + n1 = n) 
  48.     int w0, w1; // 前景所占比例, 后景所占比例(w0 = n0 / n, w0 + w1 = 1) 
  49.     double u, u0, u1; // 总平均灰度,前景平均灰度,后景平均灰度(u = w0 * u0 + w1 * u1) 
  50.     double g, gMax; // 图像类间方差,最大类间方差(g = w0*(u0-u)^2+w1*(u1-u)^2 = w0*w1*(u0-u1)^2) 
  51.     double sum_u, sum_u0, sum_u1; // 图像灰度总和,前景灰度总和, 后景平均总和(sum_u = n * u) 
  52.     int thresh; // 阈值 
  53.  
  54.     memset(pixelNum, 0, 256 * sizeof(unsigned int)); // 数组置0 
  55.  
  56.     // 统计各灰度数目 
  57.     int i, j; 
  58.     for (i = 0; i < h; i++) { 
  59.         for (j = 0; j < w; j++) { 
  60.             color = (colors[w * i + j]) & 0xFF; // 获得灰度值 
  61.             pixelNum[color]++; // 相应灰度数目加1 
  62.         } 
  63.     } 
  64.  
  65.     // 图像总点数 
  66.     n = w * h; 
  67.  
  68.     // 计算总灰度 
  69.     int k; 
  70.     for (k = 0; k <= 255; k++) { 
  71.         sum_u += k * pixelNum[k]; 
  72.     } 
  73.  
  74.     // 遍历判断最大类间方差,得到最佳阈值 
  75.     for (k = 0; k <= 255; k++) { 
  76.         n0 += pixelNum[k]; // 图像前景点数 
  77.         if (0 == n0) { // 未获取前景,直接继续增加前景点数 
  78.             continue
  79.         } 
  80.         if (n == n0) { // 前景点数包括了全部时,不可能再增加,退出循环 
  81.             break
  82.         } 
  83.         n1 = n - n0; // 图像后景点数 
  84.  
  85.         sum_u0 += k * pixelNum[k]; // 前景灰度总和 
  86.         u0 = sum_u0 / n0; // 前景平均灰度 
  87.         u1 = (sum_u - sum_u0) / n1; // 后景平均灰度 
  88.  
  89.         g = n0 * n1 * (u0 - u1) * (u0 - u1); // 类间方差(少除了n^2) 
  90.  
  91.         if (g > gMax) { // 大于最大类间方差时 
  92.             gMax = g; // 设置最大类间方差 
  93.             thresh = k; // 取最大类间方差时对应的灰度的k就是最佳阈值 
  94.         } 
  95.     } 
  96.  
  97.     return thresh; 
 
 




     本文转自winorlose2000 51CTO博客,原文链接:http://blog.51cto.com/vaero/822997如需转载请自行联系原作者



相关文章
|
8天前
|
人工智能 编解码 算法
使用 PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理
在本教程中,您将学习在阿里云交互式建模平台PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理,实现文本驱动的图像编辑功能单卡即可完成AIGC图片风格变化、背景变化和主体变化等功能。让我们一同开启这场旅程,为您的图像编辑添上无限可能性的翅膀吧。
|
7天前
|
存储 编解码 算法
图像的压缩算法--尺寸压缩、格式压缩和品质压缩
图像的压缩算法--尺寸压缩、格式压缩和品质压缩
16 0
|
13天前
|
算法
有史以来最全的图像相似度算法
有史以来最全的图像相似度算法
9 0
|
13天前
|
机器学习/深度学习 人工智能 算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
18 0
|
13天前
|
算法 数据安全/隐私保护 计算机视觉
基于DCT变换的彩色图像双重水印嵌入和提取算法matlab仿真
**算法摘要:** - 图形展示:展示灰度与彩色图像水印应用,主辅水印嵌入。 - 软件环境:MATLAB 2022a。 - 算法原理:双重水印,转换至YCbCr/YIQ,仅影响亮度;图像分割为M×N块,DCT变换后嵌入水印。 - 流程概览:两步水印嵌入,每步对应不同图示表示。 - 核心代码未提供。
|
13天前
|
算法 TensorFlow 算法框架/工具
基于直方图的图像阈值计算和分割算法FPGA实现,包含tb测试文件和MATLAB辅助验证
这是一个关于图像处理的算法实现摘要,主要包括四部分:展示了四张算法运行的效果图;提到了使用的软件版本为VIVADO 2019.2和matlab 2022a;介绍了算法理论,即基于直方图的图像阈值分割,通过灰度直方图分布选取阈值来区分图像区域;并提供了部分Verilog代码,该代码读取图像数据,进行处理,并输出结果到&quot;result.txt&quot;以供MATLAB显示图像分割效果。
|
13天前
|
算法 数据安全/隐私保护 数据格式
基于混沌序列的图像加解密算法matlab仿真,并输出加解密之后的直方图
该内容是一个关于混沌系统理论及其在图像加解密算法中的应用摘要。介绍了使用matlab2022a运行的算法,重点阐述了混沌系统的特性,如确定性、非线性、初值敏感性等,并以Logistic映射为例展示混沌序列生成。图像加解密流程包括预处理、混沌序列生成、数据混淆和扩散,以及密钥管理。提供了部分核心程序,涉及混沌序列用于图像像素的混淆和扩散过程,通过位操作实现加密。
|
13天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
1天前
|
机器学习/深度学习 算法 网络架构
基于yolov2深度学习网络的单人口罩佩戴检测和人脸定位算法matlab仿真
摘要:该内容展示了一个基于YOLOv2的单人口罩佩戴检测和人脸定位算法的应用。使用MATLAB2022A,YOLOv2通过Darknet-19网络和锚框技术检测图像中的口罩佩戴情况。核心代码段展示了如何处理图像,检测人脸并标注口罩区域。程序会实时显示检测结果,等待一段时间以优化显示流畅性。
|
4天前
|
机器学习/深度学习 算法
m基于GA-GRU遗传优化门控循环单元网络的电力负荷数据预测算法matlab仿真
在MATLAB 2022a中,一个基于遗传算法优化的GRU网络展示显著优化效果。优化前后的电力负荷预测图表显示了改进的预测准确性和效率。GRU,作为RNN的一种形式,解决了长期依赖问题,而遗传算法用于优化其超参数,如学习率和隐藏层单元数。核心MATLAB程序执行超过30分钟,通过迭代和适应度评估寻找最佳超参数,最终构建优化的GRU模型进行负荷预测,结果显示预测误差和模型性能的提升。
19 4