include
using namespace std;
#include //需要使用堆栈,对堆栈进行操作
#include "conio.h"
include "viLib.h" // 包含头文件
pragma comment( lib, "viLib.lib" ) // 包含viLib.lib库
include "viImage.h" // 包含头文件
pragma comment( lib, "viImage.lib" )
struct SplitArea
{
unsigned int w; // 分裂块图像的宽度
unsigned int h; // 分裂块图像的高度
unsigned int left; //相对源图像数据的偏移宽度
unsigned int top; // 相对源图像数据的偏移高度
};
void areaSplitCombine(unsigned char *srcImage, // 源图像数据
unsigned int Width, // 源图像的宽度
unsigned int Heigh) // 相对源图像数据的偏移高度
{
//初始区域压栈即整幅图片压栈
stack MyStack;
SplitArea splitarea;
splitarea.w = Width;
splitarea.h = Heigh;
splitarea.left = 0;
splitarea.top = 0;
MyStack.push(splitarea); //原始图像的区域信息栈
while(!MyStack.empty())
{
//区域出栈
splitarea = MyStack.top();
MyStack.pop();
int childWidthTemp[3], childHeightTemp[3];//用于存放图像分裂后的四块子图像的宽度和高度
int n, m, l;
n = (splitarea.top * Width + splitarea.left); // 该块图像的左上角像素值在数组中的下标
// 把图像分成4块,采用数组分别存储3个宽度值和3个高度值,该段程序可以处理该块图像的宽度或高度值为奇数的情况
childWidthTemp[0] = 0;
childWidthTemp[2] = (splitarea.w + 1) / 2;
childWidthTemp[1] = splitarea.w - childWidthTemp[2];//图像宽度为偶数的情况下, childWidthTemp[1]和childWidthTemp[2]无差别,
//奇数情况下childWidthTemp[2]-childWidthTemp[1]=1
childHeightTemp[0] = 0;
childHeightTemp[2] = (splitarea.h + 1) / 2;
childHeightTemp[1] = splitarea.h - childHeightTemp[2];//图像宽度为偶数的情况下, childHidthTemp[1]和childHidthTemp[2]无差别,
//奇数情况下childHidthTemp[2]-childHidthTemp[1]=1
// 计算每一块图像的属性值(均方差)
int Value;
int ValueTemp;
int i, j;//对分成的四块图像进行操作的循环
for(i = 1; i < 3; i++)
{
for(j = 1; j < 3; j++)
{
Value = 0;
m = (n + Width * childHeightTemp[i - 1] + childWidthTemp[j - 1]);
int x, y;
for(x = 0; x < childHeightTemp[i]; x++)
{
for(y = 0; y < childWidthTemp[j];y++)
{
l = (m + Width * x + y) ;//每块图像中各个像素点在存储数组中的位置下标
ValueTemp = srcImage[l];
Value = Value+ValueTemp;
}
}// 灰度值之和
if(childHeightTemp[i] * childWidthTemp[j] == 0)//分裂至最终结束时分裂块的宽度和高度其中有一个位0,那么分裂结束
{
continue;
}
if(childHeightTemp[i] * childWidthTemp[j] == 1)//分裂至单个像素时,将单个像素进行二值化
{
l = m;
if(srcImage[l] < 125)
{
srcImage[l]= 0;
}
else
{
srcImage[l] = 255;
}
continue;
}
// 各块图像的灰度平均值
int ValueS[2][2]; // 用于存储块图像的灰度值
ValueS[i - 1][j - 1] = Value / (childHeightTemp[i] * childWidthTemp[j]);
int Value1=0,ValueTemp1;
for(x = 0;x < childHeightTemp[i]; x++)
{
for(y = 0; y< childWidthTemp[j]; y++)
{
l = (m + Width * x + y) ;
ValueTemp1 = srcImage[l];
Value1 = Value1+(ValueTemp1- ValueS[i - 1][j - 1])*(ValueTemp1- ValueS[i - 1][j - 1]);
}
}
// 各块图像的均方差
int ValueS1[2][2]; // 用于存储块图像的均方差
ValueS1[i - 1][j - 1]= Value1 / (childHeightTemp[i] * childWidthTemp[j]);
// 对每一块进行判断是否需要分裂
// 分裂原则: 图像的均方差超过某个阈值是需要分裂
if(ValueS1[i - 1][j - 1] > 100) // 均方差大于某个阈值时需要分裂
{ SplitArea childarea;
childarea.w = childWidthTemp[j];
childarea.h = childHeightTemp[i];
childarea.left = splitarea.left + childWidthTemp[j - 1];
childarea.top = splitarea.top + childHeightTemp[i - 1];
MyStack.push(childarea);
}
else // 如果不需要分裂, 则进行合并(直接填充该块图像为灰度值的平均值)
{
for(x = 0; x < childHeightTemp[i]; x++)
{
for(y = 0; y < childWidthTemp[j]; y++)
{
l = (m + Width * x + y) ;
srcImage[l] =ValueS[i - 1][j - 1];
}
}
}
}
}
}
return;
}
int main (int argc, char * const argv[])
{
int rv;
int PixelFormat = 24, Width, Height;
unsigned char * pImg;
unsigned char * pBin;
if ( argc < 2 )
{
fprintf( stderr, "Usage: GetContour.exe image\n" ) ;
return 0 ;
}
rv = viGetImageWH( argv[1], Width, Height ) ;
if ( rv == 0 )
{
printf( "Could not get image. Program exits!\n" );
exit( 0 );
}
pImg = new unsigned char [ Width*Height*PixelFormat/8 ];
viReadImageFile( argv[1], pImg, Width, Height, PixelFormat );
pBin = new unsigned char [Width*Height];
viColor24toGray8(pImg, Width, Height,1,pBin);
areaSplitCombine( pBin, Width, Height);
viNamedWindow( "Image", GUI_WINDOW_AUTOSIZE );
viShowImage( "Image",pBin, Width, Height, 8, 0 );
viWaitKey( 0 );
delete [] pImg;
delete [] pBin;
viDestroyAllWindows();
return 0;
}