如何根据在以下方法的情况下实现图像二值化

时间:2022-05-02 19:19:05
如何根据在以下方法的情况下实现图像二值化
初次接触图像处理,已经实现如下方法。
通过LoadBmp载入bmp图像,通过Draw方法显示该图像,在资料上找了个大律法求阈值,但是在网上找的二值化算法的参数跟本人已写的方法配不起来,如何在下面情况下求 直方图从而根据大律法阈值来实现 二值化


// ImageProcess.h: CImageProcess 的接口类

#ifndef _CPROCESS_H
#define _CPROCESS_H

class CImageProcess : public CObject
{
protected:
BYTE *m_pDib, *m_pDib1; // 指向设备无关位图的指针

BITMAPINFO *m_pBI; // 位图信息的指针
BYTE *m_pBits; // 像素数据的指针

int wid; // 宽度
int hei; // 高度
int bits; // 像素总位数
int bpl; // 每行字节数
int bpp; // 每像素字节数
int colors; // 颜色数
long size; // 图像尺寸



public:
CImageProcess(); // 构造函数
~CImageProcess(); // 析构函数

BYTE* CreateDib(int wid, int hei, int bits); // 建立设备无关位图
void SetDibParam(BYTE *m_lpdib); // 设置设备无关位图参数
BOOL LoadBmp(const char *); // 读入BMP文件
BOOL Draw(CDC* pDC); // 显示图像
int Otsu(long *pg, long *pg1); // 大律法取阈值(pg为存放像素点数的数组,即图像的直方图曲线;pg1为输出判别函数曲线,值为0时无曲线输出;返回值为确定的阈值)
};

#endif //!_CPROCESS_H

-----------------------------------------------------------------------------------------------------------------------------
-------------------------实现类-----------------------------------------------------------------------------------------------

// ImageDoc.cpp : 

#include "stdafx.h"
#include "math.h"
#include "VCImage.h"
#include "ImageProcess.h"
#include "CDib_VC.h"

CImageProcess::CImageProcess() // 构造函数
{
m_pDib = m_pDib1 = NULL; // 设备无关位图初始化,清零
}

CImageProcess::~CImageProcess() // 析构函数
{
if( m_pDib != NULL )
delete [] m_pDib;
if( m_pDib1 != NULL )
delete [] m_pDib1;
}

BYTE* CImageProcess::CreateDib(int wid, int hei, int bits) // 建立设备无关位图
{
BITMAPINFOHEADER bmi = { 40, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
long size,colors;
BYTE *pDib = 0;

bmi.biWidth = wid; // 宽度
bmi.biHeight = hei; // 高度
bmi.biBitCount = (WORD)bits; // 每像素位数

if( bits <= 8 ) colors = 1 << bits; // 计算颜色数
else colors = 0;
size = 40L + colors * 4 + ( ( wid * bits ) / 32 * 4 ) * hei; // 计算设备无关位图的字节数
pDib = new BYTE [size]; // 申请内存单元
memcpy( pDib, &bmi, 40 ); // 复制位图文件头
return( pDib ); // 返回设备无关位图指针
}

void CImageProcess::SetDibParam( BYTE *pDib ) // 设置设备无关位图参数
{
BITMAPINFOHEADER *pBIH;

m_pBI = (BITMAPINFO *) pDib; // 得位图信息指针
pBIH = (BITMAPINFOHEADER *) pDib; // 得位图信息头指针

wid = pBIH->biWidth; // 从位图信息头中取出图像参数
hei = pBIH->biHeight;
bits = pBIH->biBitCount;
colors = 1 << pBIH->biBitCount; // 像素位数与调色板数的关系
if( pBIH->biBitCount > 8 ) colors = 0; // 真彩色图像无调色板
else if( pBIH->biClrUsed != 0) colors = pBIH->biClrUsed; // 如果使用的色彩数不等于0

m_pBits = &pDib[sizeof(BITMAPINFOHEADER) + colors * sizeof(RGBQUAD)]; // 得像素数据指针

bpl = ( wid * bits + 31 ) / 32 * 4; // 计算每行字节数
bpp = ( bits + 7 ) / 8; // 计算每像素字节数
size = 40L + colors * 4 + bpl * hei; // 计算图像尺寸
}

BOOL CImageProcess::LoadBmp( const char *pszFilename ) // 读入BMP图像文件
{
CFile cf;
BITMAPFILEHEADER BFH;
DWORD dwDibSize;

if( !cf.Open( (LPCTSTR)pszFilename, CFile::modeRead ) )
return(FALSE);
dwDibSize = cf.GetLength() - sizeof( BITMAPFILEHEADER ); // 计算设备无关位图尺寸

if( m_pDib != NULL ) delete [] m_pDib; // 删除原来图像
m_pDib = new BYTE [dwDibSize]; // 建立原始图像
if( m_pDib == NULL )
return(FALSE);

if( cf.Read( &BFH, sizeof(BITMAPFILEHEADER) ) != sizeof(BITMAPFILEHEADER) ||
BFH.bfType != 'MB' ||
cf.Read( m_pDib, dwDibSize ) != dwDibSize )
{ // 读入图像
delete [] m_pDib;
return(FALSE);
}
cf.Close();

if( m_pDib1 != NULL ) delete [] m_pDib1; // 删除原备份图像
m_pDib1 = new BYTE [dwDibSize]; // 建立备份图像
if( m_pDib1 == NULL ) return(FALSE);
memcpy( m_pDib1, m_pDib, dwDibSize ); //  原始图像复制到备份中
return(TRUE);
}

BOOL CImageProcess::Draw( CDC* pDC) // 显示设备无关位图
{
if( m_pDib == NULL )
return(FALSE);

SetDibParam( m_pDib ); // 设置设备无关位图参数
StretchDIBits( pDC->m_hDC, 0, 0, wid, hei,
0, 0, wid, hei,
m_pBits, m_pBI,
DIB_RGB_COLORS, SRCCOPY ); // 显示位图
return(TRUE);
}

int Otsu(long *pg, long *pg1) // 大律法取阈值(pg为存放像素点数的数组,即图像的直方图曲线;pg1为输出判别函数曲线,值为0时无曲线输出;返回值为确定的阈值)
{
int i,j,p;
double A,B,An,Bn,u,v,qqq[256],max,min;

An = Bn = 0;
for(i = 0; i < 256; i++)
{
An += pg[i];
Bn += pg[i] * (i + 1);
}
for(j = 0; j < 256; j++)
{
A = B = 0;
for(i = 0; i <= j; i++)
{
A += pg[i];
B += pg[i] * (i + 1);
}
if(A) u = B / A;
else u = 0;
if(An - A) v = (Bn - B) / (An - A);
else v = 0;
qqq[j] = A * (An - A) * (u - v) * (u - v); // 计算类间方差
}

max = min = qqq[0];
p = 0;
for(i = 1; i < 256; i++) // 寻找判别函数最大值
{
if(qqq[i] > max)
{
max = qqq[i];
p = i;
}
else if(qqq[i] < min) min = qqq[i];
}

if(pg1 != 0)
{
for(i = 0; i < 256; i++)
{
pg1[i] = (long) (120 * (qqq[i] - min) / (max - min)); // 判别函数作标度转换
}
}
return (p); // 取判别函数最大值的灰度为其阈值
}



8 个解决方案

#1


不是很明白楼主的意思,二值化根据你自己的需要啊,你是想把你发的图片二值化吗?直接保存为1位图像不就好了吗? 二值化要根据具体情况来做啊。

#2


就是把类似已发的这种文本图像二值化,再进行行分割,字分割等,
问题我对图像这块不懂,现不知如何二值化

#3


首先,我记得不是大律法,是大津法,呵呵。

Otsu你直接用不就可以了,输入图像数组,它会自动计算类间方差最大的阈值,不就返回数值了吗?
你为什么要求直方图?

#4


BYTE            * m_pDib, *m_pDib1;    //    指向设备无关位图的指针

int Otsu( long *pg, long *pg1)    //    大津法取阈值(pg为存放像素点数的数组,即图像的直方图曲线;pg1为输出判别函数曲线,值为0时无曲线输出;返回值为确定的阈值)


其中参数pg为直方图曲线,pg1为输出判别函数;
载入图像时只获得图像指针,如何求得pg和pg1以作为Otsu的参数?

下面是图像黑白二值化:

BOOL CImageProcess::Binary(LPSTR lpDIBBits,BYTE bThre)
{
int i,j,LineTypes;
GetSize(lpDIBBits);
LineTypes=WIDTHBYTES(bmWidth*8);
for(i=0;i<bmHeight;i++)
for(j=0;j<bmWidth;j++)
{
lpSrc=(unsigned char*)lpDIBBits
+LineTypes*(bmHeight-1-i)+j;
if((*lpSrc)<bThre)
*lpSrc=0;
else
*lpSrc=255;
}
return true;
}

//LPSTR lpDIBBits:指向源DIB图像的指针,
对这个指针我一直不明白怎么样获取,使用LoadBmp(const char *)得到的是指向设备无关位图的指针m_pDib和m_pDib1,类型不一样,怎样转过来??

#5


该回复于2009-05-11 10:13:11被版主删除

#6


自己顶起来,期待答案

#7


又沉下去了,再顶起来

#8


二值图像是怎么显示的啊?

#1


不是很明白楼主的意思,二值化根据你自己的需要啊,你是想把你发的图片二值化吗?直接保存为1位图像不就好了吗? 二值化要根据具体情况来做啊。

#2


就是把类似已发的这种文本图像二值化,再进行行分割,字分割等,
问题我对图像这块不懂,现不知如何二值化

#3


首先,我记得不是大律法,是大津法,呵呵。

Otsu你直接用不就可以了,输入图像数组,它会自动计算类间方差最大的阈值,不就返回数值了吗?
你为什么要求直方图?

#4


BYTE            * m_pDib, *m_pDib1;    //    指向设备无关位图的指针

int Otsu( long *pg, long *pg1)    //    大津法取阈值(pg为存放像素点数的数组,即图像的直方图曲线;pg1为输出判别函数曲线,值为0时无曲线输出;返回值为确定的阈值)


其中参数pg为直方图曲线,pg1为输出判别函数;
载入图像时只获得图像指针,如何求得pg和pg1以作为Otsu的参数?

下面是图像黑白二值化:

BOOL CImageProcess::Binary(LPSTR lpDIBBits,BYTE bThre)
{
int i,j,LineTypes;
GetSize(lpDIBBits);
LineTypes=WIDTHBYTES(bmWidth*8);
for(i=0;i<bmHeight;i++)
for(j=0;j<bmWidth;j++)
{
lpSrc=(unsigned char*)lpDIBBits
+LineTypes*(bmHeight-1-i)+j;
if((*lpSrc)<bThre)
*lpSrc=0;
else
*lpSrc=255;
}
return true;
}

//LPSTR lpDIBBits:指向源DIB图像的指针,
对这个指针我一直不明白怎么样获取,使用LoadBmp(const char *)得到的是指向设备无关位图的指针m_pDib和m_pDib1,类型不一样,怎样转过来??

#5


该回复于2009-05-11 10:13:11被版主删除

#6


自己顶起来,期待答案

#7


又沉下去了,再顶起来

#8


二值图像是怎么显示的啊?