Procesamiento simple de imágenes basado en easyx 2 (lenguaje C)

 Este artículo escribe principalmente el procesamiento de la binarización de la imagen La binarización de la imagen se refiere solo a dos casos de píxeles de imagen, 0 y 255. La idea básica es primero escalar la imagen en escala de grises. En el artículo anterior, hay códigos detallados, y el siguiente paso es procesar imágenes en escala de grises. Ahora, desde el caso más simple, la binarización es elegir un umbral. Aquí, por ejemplo, el umbral es 200. El valor de gris mayor que 200 se establece en 255, y el valor de gris menor que 200 se establece en gris 0.

Aquí primero doy el código más simple, el umbral aquí se establece de acuerdo con mi propio sentimiento:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <math.h>
int image[1500][1000];
IMAGE img1;
int imagHight,imagWidth;
int threshold = 0;//阈值
int main()
{
	int i,j,k;
	// 读取图片至绘图窗口
	loadimage(&img1, _T("D:\\testh.bmp"));
	imagHight = img1.getheight();
	imagWidth = img1.getwidth();
	total = imagHight*imagWidth;
	initgraph(imagWidth,imagHight, SHOWCONSOLE|NOCLOSE|NOMINIMIZE);
    putimage(0, 0, &img1);
	DWORD* pMem = GetImageBuffer();

	//图像灰度化
	for(i = 0; i <imagHight; i++)
	{
		for(j=0;j<imagWidth;j++)
	  {
	   *pMem = BGR(*pMem);
	   image[i][j]  = (GetRValue(*pMem)*299+GetGValue(*pMem)*587+GetBValue(*pMem)*114+500)/1000;  
	   *pMem = RGB(image[i][j],image[i][j],image[i][j]);
	   pMem++;
		}
	}
	 pMem -= imagHight*imagWidth; //将指针重新指向第一个像素点
	
    //二值化
	for(i = 0; i <imagHight; i++)
	{
		for(j=0;j<imagWidth;j++)
	  {
	     if(image[i][j]>200)image[i][j] = 255;
		 else image[i][j] = 0;
		 *pMem = RGB(image[i][j],image[i][j],image[i][j]);
	      pMem++;
	  }
	}
	FlushBatchDraw();
    _getch();
	closegraph();
}

El cuadro de efectos es el siguiente:

Imagen original

El umbral es 200

 if(image[i][j]>200)image[i][j] = 255;

Aquí, el umbral 200 anterior se cambia a 50. Se puede ver que la mayoría de las escalas de grises son mayores que 50, por lo que la mayoría de las imágenes son blancas (el valor de escala de grises es 255).

 Aquí también vemos la importancia de la selección del umbral, los diferentes umbrales, el grado de separación del primer plano y el fondo son diferentes, cómo elegir el umbral más apropiado es la clave para la binarización.

 Así que investigué el algoritmo binario otsu, también conocido como algoritmo Otsu. Aquí me refiero a este artículo, puedes echar un vistazo, todavía es relativamente fácil de entender.             https://blog.csdn.net/qingzhuyuxian/article/details/88819810#commentBox

 

Aquí está el programa que escribí yo mismo:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <math.h>
int image[1500][1000];
int Histogram[256]={0};
IMAGE img1;
int imagHight,imagWidth;
double total;//像素点的总数
double variances[256];//每个阈值对应的组内方差
double bvariances;//背景的方差
double fvariances;//前景的方差
double bproportion;//背景的像素点占的比例
double fproportion;//前景的像素点占的比例
double count;//用来记录像素点的个数
double bmean;//背景的平均值
double fmean;//前景的平均值
double min_value;//最小的方差
int threshold = 0;//阈值
int main()
{
	int i,j,k;
	// 读取图片至绘图窗口
	loadimage(&img1, _T("D:\\testh.bmp"));
	imagHight = img1.getheight();
	imagWidth = img1.getwidth();
	total = imagHight*imagWidth;
	initgraph(imagWidth,imagHight, SHOWCONSOLE|NOCLOSE|NOMINIMIZE);
    putimage(0, 0, &img1);
	DWORD* pMem = GetImageBuffer();
	_getch();
	//图像灰度化
	for(i = 0; i <imagHight; i++)
	{
		for(j=0;j<imagWidth;j++)
	  {
	   *pMem = BGR(*pMem);
	   image[i][j]  = (GetRValue(*pMem)*299+GetGValue(*pMem)*587+GetBValue(*pMem)*114+500)/1000;  
	   *pMem = RGB(image[i][j],image[i][j],image[i][j]);
	   pMem++;
		}
	}
	 pMem -= imagHight*imagWidth; //将指针重新指向第一个像素点

	//获取直方图

	for(i = 0; i <imagHight; i++)
    {
	 for(j=0;j<imagWidth;j++)
	  {
	     Histogram[image[i][j]]++; 
	  }
	}

	//求组内方差最小的那个阈值
	for(i=0;i<256;i++) //从阈值为0到255 分别计算对应的组内方差
	{
		count = 0;
		bmean = 0;
		bproportion = 0;
		bvariances = 0;
		for(j=0;j<i;j++)
		{
			 count += Histogram[j]; 
			 bmean = Histogram[j]*j;
		}
		bproportion = count / total;
		bmean = (count==0)?0:(bmean/count);
		for(k=0;k<i;k++)
		{
			bvariances += pow(k-bmean,2)*Histogram[k]; 
		}

		bvariances = (count==0)?0:bvariances / count;

		count = 0;
		fmean = 0;
		fproportion = 0;
		fvariances = 0;

		for(j=i;j<256;j++)
		{
			 count += Histogram[j]; 
			 fmean = Histogram[j]*j;
		}
		fproportion = count / total;
		fmean = (count==0)?0:(fmean/count);
		for(k=i;k<256;k++)
		{
			fvariances += pow(k-fmean,2)*Histogram[k]; 
		}

		fvariances = (count==0)?0:fvariances / count;

		variances[i] = bproportion * bvariances + fproportion * fvariances;
	}

	//找到最小方差值对应的那个阈值
	min_value = variances[0];
	for(i=1;i<256;i++)
	{
		if(min_value>variances[i])
		{
			min_value = variances[i];
			threshold = i;
		}
	}
	
	printf("threshold:%d",threshold); //打印最佳阈值
    //二值化
	for(i = 0; i <imagHight; i++)
	{
		for(j=0;j<imagWidth;j++)
	  {
	     if(image[i][j]>threshold)image[i][j] = 255;
		 else image[i][j] = 0;
		 *pMem = RGB(image[i][j],image[i][j],image[i][j]);
	      pMem++;
	  }
	}
	FlushBatchDraw();
    _getch();
	closegraph();
}

Imagen del efecto:

El umbral calculado aquí es 185

 

Hay otras formas de encontrar el umbral, que no se enumeran aquí, puede verificarlo si está interesado.

Publicado 7 artículos originales · ganó 13 · vistas 2096

Supongo que te gusta

Origin blog.csdn.net/qq_39036834/article/details/97750403
Recomendado
Clasificación