① Sobel算子检测边缘
void CDemoView::Onsobel()
{
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR)::GlobalLock((HGLOBAL)dib);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB; //信息头指针
int biByteCount = phead->biBitCount / 8; //每像素字节数
if (biByteCount == 3)
{
::GlobalUnlock(dib);
return;
} //彩色图不做处理
int w = phead->biWidth;
int h = phead->biHeight;
int lineByte = (biByteCount * w + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB); //像素位置指针,unsigned char取值范围是0~255(一个字节)
unsigned char *buf = new unsigned char[w*h]; //新内存存放运算结果
unsigned char c[2]; //存2个模板的卷积结果
unsigned char a[8]; //取邻域元素
int r; //存卷积结果
for (int i = 1; i < h - 1; i++) {
for (int j = 1; j < w - 1; j++) {
a[0] = *(lpDIBBits + (i + 1) * lineByte + j - 1);
a[1] = *(lpDIBBits + (i + 1) * lineByte + j);
a[2] = *(lpDIBBits + (i + 1) * lineByte + j + 1);
a[3] = *(lpDIBBits + i * lineByte + j + 1);
a[4] = *(lpDIBBits + (i - 1) * lineByte + j + 1);
a[5] = *(lpDIBBits + (i - 1) * lineByte + j);
a[6] = *(lpDIBBits + (i - 1) * lineByte + j - 1);
a[7] = *(lpDIBBits + i * lineByte + j - 1);
c[0] = abs(-a[0] + a[2] + a[3] * 2 + a[4] - a[6] - a[7] * 2);
c[1] = abs(a[0] + a[1] * 2 + a[2] - a[4] - a[5] * 2 - a[6]);
r = 2 * pow(c[0] * c[0] + c[1] * c[1], 0.5); //综合垂直与水平两个方向,乘2再放大一下,结果变亮一些
if (r > 255)
r = 255;
*(buf + i * w + j) = r;
}
}
for (int i = 1; i < h - 1; i++) {
for (int j = 1; j < w - 1; j++) {
*(lpDIBBits + i * lineByte + j) = *(buf + i * w + j);
}
}
delete[]buf;
::GlobalUnlock(dib);
Invalidate(); //区域重绘
}
② 直方图均衡
void CDemoView::OnHistEqual()
{
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR)::GlobalLock((HGLOBAL)dib);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB; //信息头指针
int biByteCount = phead->biBitCount / 8; //每像素字节数
if (biByteCount == 3)
{
::GlobalUnlock(dib);
return;
} //彩色图不做处理
int w = phead->biWidth;
int h = phead->biHeight;
int lineByte = (biByteCount * w + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB); //像素位置指针,unsigned char取值范围是0~255(一个字节)
double p[256];
for (int i = 0; i < 256; i++) {
p[i] = 0;
}
unsigned char value[256];
//统计直方图
unsigned char idx;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idx = *(lpDIBBits + i * lineByte + j);
p[idx] += 1.0 / (w*h);
}
}
//累加
for (int i = 1; i < 256; i++) {
p[i] += p[i - 1];
}
//计算新的灰度值
for (int i = 0; i < 256; i++) {
value[i] = (unsigned char)(p[i] * 255);
}
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idx = *(lpDIBBits + i * lineByte + j);
*(lpDIBBits + i * lineByte + j) = value[idx];
}
}
::GlobalUnlock(dib);
Invalidate(); //区域重绘
}
③ 大津阈值
void CDemoView::Onotsu()
{
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR)::GlobalLock((HGLOBAL)dib);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB; //信息头指针
int biByteCount = phead->biBitCount / 8; //每像素字节数
if (biByteCount == 3)
{
::GlobalUnlock(dib);
return;
} //彩色图不做处理
int w = phead->biWidth;
int h = phead->biHeight;
int lineByte = (biByteCount * w + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB); //像素位置指针,unsigned char取值范围是0~255(一个字节)
//统计直方图
float p[256];
for (int i = 0; i < 256; i++) {
p[i] = 0;
}
unsigned char idx;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idx = *(lpDIBBits + i * lineByte + j);
p[idx] += 1.0 / (w*h);
}
}
//计算全图均值
float u = 0;
for (int i = 0; i < 256; i++) {
u += p[i] * i;
}
//统计类间最大方差diff(th)
float diff = 0;
float diffmax = 0;
int T = 0;
for (int th = 1; th < 256; th++) { //分为小于和大于等于两部分
float w0 = 0;
float w1 = 0;
float u0 = 0;
float u1 = 0;
//w0 and u0
for (int i = 0; i < th; i++) {
w0 += p[i];
u0 += p[i] * i;
}
if (w0 == 0.0) //注意这里如果前半部分没有像素,就不能当作阈值
continue;
else
u0 = u0 / w0;
//w1 and u1
for (int i = th; i < 256; i++) {
u1 += p[i] * i;
}
w1 = 1.0 - w0;
if (w1 == 0.0)
continue;
else
u1 = u1 / w1;
//类间方差diff
diff = w0 * pow((u0 - u), 2) + w1 * pow((u1 - u), 2);
//diff = w0 * w1 * pow((u0 - u1), 2);
if (diffmax < diff) {
diffmax = diff;
T = th;
}
}
//阈值分割
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (*(lpDIBBits + i * lineByte + j) < T)
*(lpDIBBits + i * lineByte + j) = 0;
else
*(lpDIBBits + i * lineByte + j) = 255;
}
}
::GlobalUnlock(dib);
Invalidate(); //区域重绘
}
:
(1)大津阈值算法中,注意遍历的时候如果小于原图灰度最小值或者大于灰度最大值,则不取;
(2)大津阈值算法中,两部分的均值计算要思考正确;
(3)C语言给变量赋值的时候要考虑好变量的数据类型;
(4)在形如x += *
的代码中,要处理好x
的初值;
(5)傅里叶反变换去噪时,实部和虚部都要做处理。
麻瓜写于2018/11/30