江门模板建站哪家好,福州公司排名,著名网站设计师,刚刚地震最新消息今天前言
#xff08;1#xff09;在上一节中#xff0c;我们学习了对图像的固定二值化处理#xff0c;可以将原始图像处理成二值化的黑白图像#xff0c;这里面的本质就是将原来的二维数组进行了处理#xff0c;处理后的二维数组里的元素都是0和255两个值。
#xff08;2…前言
1在上一节中我们学习了对图像的固定二值化处理可以将原始图像处理成二值化的黑白图像这里面的本质就是将原来的二维数组进行了处理处理后的二维数组里的元素都是0和255两个值。
2固定阈值二值化的使用是比赛过程中每一处地方的二值化阈值都是同一个值而赛道的不同地方以同一个阈值二值化出来的图像可能不合适甚至不能正常循迹。
3为了适应赛道上的不同环境很多同学会采用动态二值化即对于采集到的不同图像通过算法计算出合适的阈值来进行二值化处理最后的二值化效果可能会比固定阈值化好一些因为也有不少同学在比赛中采用固定阈值二值化处理最后拿到了国奖所以哪个方法更好还真不好说主要根据实际情况看自己的作品。
4毋庸置疑大津法会增加算法处理处理时间肯定比固定阈值二值化长。
概念
对于图像处理入门建议大家可以去看这篇文章
详解-OTUS(大津法-最大类间方差)原理及C语言代码实现-CSDN博客
但是你不想看也没关系请继续看我后面的内容你只需要理解到一个点大津法就是一个对二维数组处理后会得到一个值的算法而这个值就是我们二值化要的阈值。想要搞清楚大津法原理请移步上面的文章进行学习我这里只进行简要介绍。
大津法 大津法阈值采用最大类间方差的原理适合于图像灰度分布整体呈现“双峰”的情况。大津法会自动找出一个阈值使得分割后的两部分类间方差最大。 最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出是一种确定图像二值化分割阈值的算法。算法假设图像像素能够根据全局阈值被分成背景[background]和目标[objects]两部分。然后计算该最佳阈值来区分这两类像素使得两类像素区分度最大。
大津法阈值采用最大类间方差的原理适合于图像灰度分布整体呈现“双峰”的情况。大津法会自动找出一个阈值使得分割后的两部分类间方差最大。 特性
大津法对噪音十分敏感在处理之前应对图片进行去噪处理。如果图像有存在局部噪声则会影响大津法的判断当目标与背景的面积比例悬殊的时候类间方差函数可能呈现双峰或者多峰这个时候 大津法的效果不好
1双峰图像目标和背景面积差距不大可以很好的判断如下 2当图像中的目标与背景的面积相差很大时灰度直方图没有明显的双峰或者两个峰的大小相差很大分割效果不佳 代码实现
一般大津法代码如下
你只需要将我的代码复制粘贴到images.c文件中把这个函数在cpu1.c中调用即可
images.c
#include zf_common_headfile.huint8 mt9v03x_image_BandW[MT9V03X_H][MT9V03X_W];/*begin 大津法比赛 begin*/
//快速大津法二值化 pixelSum width * height/4;
//-------------------------------------------------------------------------------------------------------------------
// brief 快速大津
// return uint8
// since v1.1
// Sample usage: OTSU_Threshold otsuThreshold(mt9v03x_image_dvp[0]);//大津法阈值
//-------------------------------------------------------------------------------------------------------------------
uint8 otsuThreshold_fast(uint8 *image) //注意计算阈值的一定要是原图像
{
#define GrayScale 256int Pixel_Max0;int Pixel_Min255;uint16 width MT9V03X_W; //宽100uint16 height MT9V03X_H; //高80int pixelCount[GrayScale]; //各像素GrayScale的个数pixelCount 一维数组float pixelPro[GrayScale]; //各像素GrayScale所占百分比pixelPro 一维数组int i, j, pixelSum width * height/4; //pixelSum是获取总的图像像素个数的1/4相应下面轮询时高和宽都是以2为单位自增uint8 threshold 0;
// uint8 last_threshold 0;uint8* data image; //指向像素数据的指针//清零for (i 0; i GrayScale; i){pixelCount[i] 0;pixelPro[i] 0;}uint32 gray_sum0; //每次执行到这会将gray_sum清零//统计灰度级中每个像素在整幅图像中的个数for (i 0; i height; i2) //高{for (j 0; j width; j2) //宽{pixelCount[(int)data[i * width j]]; //将当前的点的像素值作为计数数组的下标gray_sum(int)data[i * width j]; //灰度值总和if(data[i * width j]Pixel_Max) Pixel_Maxdata[i * width j];if(data[i * width j]Pixel_Min) Pixel_Mindata[i * width j];}}//计算每个像素值的点在整幅图像中的比例for (i Pixel_Min; i Pixel_Max; i){pixelPro[i] (float)pixelCount[i] / pixelSum;}//遍历灰度级[0,255]float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax 0;w0 w1 u0tmp u1tmp u0 u1 u deltaTmp 0;for (j Pixel_Min; j Pixel_Max; j){w0 pixelPro[j]; //背景部分每个灰度值的像素点所占比例之和 即背景部分的比例u0tmp j * pixelPro[j]; //背景部分 每个灰度值的点的比例 *灰度值w11-w0;u1tmpgray_sum/pixelSum-u0tmp;u0 u0tmp / w0; //背景平均灰度u1 u1tmp / w1; //前景平均灰度u u0tmp u1tmp; //全局平均灰度deltaTmp (float)(w0 *w1* (u0 - u1)* (u0 - u1)) ;if (deltaTmp deltaMax){deltaMax deltaTmp;threshold (uint8)j;}if (deltaTmp deltaMax){break;}}return threshold;
}
/*end 大津法比赛 end*//*begin 大津法学习 begin*/
//------------------摄像头参数--------------//
uint8 image_threshold 46; //图像阈值 0~255
uint8 dis_image[60][80];uint8 otsuThreshold(uint8 *image, uint16 width, uint16 height)
{#define GrayScale 256int pixelCount[GrayScale] {0};//每个灰度值所占像素个数float pixelPro[GrayScale] {0};//每个灰度值所占总像素比例int i,j;int Sumpix width * height; //总像素点uint8 threshold 0;uint8* data image; //指向像素数据的指针//统计灰度级中每个像素在整幅图像中的个数for (i 0; i height; i){for (j 0; j width; j){pixelCount[(int)data[i * width j]]; //将像素值作为计数数组的下标// pixelCount[(int)image[i][j]]; 若不用指针用这个}}float u 0;for (i 0; i GrayScale; i){pixelPro[i] (float)pixelCount[i] / Sumpix; //计算每个像素在整幅图像中的比例u i * pixelPro[i]; //总平均灰度}float maxVariance0.0; //最大类间方差float w0 0, avgValue 0; //w0 前景比例 avgValue 前景平均灰度for(i 0; i 256; i) //每一次循环都是一次完整类间方差计算 (两个for叠加为1个){w0 pixelPro[i]; //假设当前灰度i为阈值, 0~i 灰度像素所占整幅图像的比例即前景比例avgValue i * pixelPro[i];float variance pow((avgValue/w0 - u), 2) * w0 /(1 - w0); //类间方差if(variance maxVariance){maxVariance variance;threshold (uint8)i;}}return threshold;
}/*end 大津法学习 end*///图像二值化
//0 - 255
//黑 - 白
void Set_image_towvalues(uint8 value)
{uint8 temp_valude;//暂存灰度值for(uint8 i 0;i MT9V03X_H;i)//高{for(uint8 j 0;j MT9V03X_W;j)//宽{temp_valude mt9v03x_image[i][j];if(temp_valude value){mt9v03x_image_BandW[i][j] 0;//黑}else{mt9v03x_image_BandW[i][j] 255;//白}}}
}
images.h
#ifndef CODE_IMAGES_H_
#define CODE_IMAGES_H_extern uint8 mt9v03x_image_BandW[MT9V03X_H][MT9V03X_W];void Set_image_towvalues(uint8 value);
uint8 otsuThreshold(uint8 *image, uint16 width, uint16 height);
uint8 otsuThreshold_fast(uint8 *image);
#endif /* CODE_IMAGES_H_ */
但是不优化大津法的代码图像处理时间较长所以大家又将“大津法”优化成了“快速大津法”代码也在上面公布了照我如下调用即可。
cpu1.c
void core1_main(void)
{disable_Watchdog(); // 关闭看门狗interrupt_global_enable(0); // 打开全局中断// 此处编写用户代码 例如外设初始化代码等mt9v03x_init();//初始化摄像头// 此处编写用户代码 例如外设初始化代码等cpu_wait_event_ready(); // 等待所有核心初始化完毕while (TRUE){// 此处编写需要循环执行的代码TFT180_SHOW();if(mt9v03x_finish_flag) //一幅图像完全采集完毕后再进行图像的显示判断和显示{//Set_image_towvalues(150); //固定阈值二值化BandW_threshold otsuThreshold_fast(mt9v03x_image[0]);//大津法得到动态阈值BandW_thresholdSet_image_towvalues(BandW_threshold); //动态阈值二值化得到二维数组mt9v03x_image_BandWtft180_displayimage03x(mt9v03x_image_BandW[0],MT9V03X_W,MT9V03X_H);//显示二值化后的图像mt9v03x_finish_flag 0;//图像显示完成后才对标志位清零}// 此处编写需要循环执行的代码}
}
通过调用大津法处理函数将原始图像进行动态阈值二值化处理也是会在显示屏上得到黑白图像固定阈值二值化和动态阈值二值化处理哪个效果好还得看实际情况。