首先是边缘检测,加上原图像是图像锐化。
直方图均衡:把原始图的直方图变换为均匀分布的形式,增加像素灰度值的动态范围,提高图像对比度。
主要步骤:先统计各个像素占全部像素的比例,然后像素x的 直方图均衡后的像素值就是(x的比例+所有像素值比x小的比例)*255。实现图像均衡的结果。
实验结果:
原图像:
直方图均衡后的图像:
代码:(是在MFC上实现的,课程祖传模板)
void CDemoView::OnImagestretchingHistogramequalization()
{
// TODO: 在此添加命令处理程序代码
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)dib);
int width = ::DIBWidth(lpDIB);
int height = ::DIBHeight(lpDIB);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB;
int biBitCount = phead->biBitCount / 8;
if (biBitCount != 1)
{
::MessageBox(0, "ERROR!NOT GRAY LEVEL IMAGE!", NULL, MB_OK);
::GlobalUnlock(dib);
return;
}
int lineByte = (width * biBitCount + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB);
int palSize = ::PaletteSize((LPSTR)lpDIB); //调色板尺寸
HANDLE dibNew = ::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
LPSTR lpDIBNew = (LPSTR) ::GlobalLock(dibNew);
::memcpy((unsigned char*)lpDIBNew, (unsigned char*)lpDIB, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
unsigned char *lpDIBBitsNew = (unsigned char *)::FindDIBBits(lpDIBNew);
int max = 0;
int min = 255;
int data;
int i, j;
double pix[256];
for (i = 0;i < 256;++i) {
pix[i] = 0;
}
for (i = 0;i < height;i++) {
for (j = 0;j < width;j++) {
data = *(lpDIBBits + i * lineByte + j);
pix[data]++;
}
}
for (i = 1;i < 256;++i) {
pix[i] = pix[i] + pix[i - 1];
}
for (i = 1;i < 256;++i) {
pix[i] = pix[i]/width/height*255;
}
for (i = 0;i < height;i++) {
for (j = 0;j < width;j++) {
*(lpDIBBitsNew + i * lineByte + j) = (int)(pix[*(lpDIBBits + i * lineByte + j)] + 0.5);
}
}
::GlobalUnlock(dib);
::GlobalUnlock(dibNew);
CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
CDemoView* pView = (CDemoView*)pFrame->MDIGetActive()->GetActiveView();
CDemoDoc* pDocNew = pView->GetDocument();
pDocNew->ReplaceHDIB((HDIB)dibNew);
pDocNew->InitDIBData();
pDocNew->UpdateAllViews(pView);
Invalidate();
}
laplace算子:
采用参考点匹配来计算旋转参数:
二维旋转可以用一下方程拟合:
u,v是原图像坐标。x,y是徐艳转后图像的坐标。
记下七组点的坐标,采用最小二乘法计算系数。
代码如下路所示:
函数采用了eigen库的矩阵Matrixxd模块, 其中七组点的数量根据交互的形式记在vector
void CDemoView::OnLeastsquaremethodk()
{
// TODO: 在此添加命令处理程序代码
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)dib);
int height = ::DIBHeight(lpDIB);
int width = ::DIBWidth(lpDIB);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB;
int biBitCount = phead->biBitCount / 8;
int lineByte = (width * biBitCount + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB);
int palSize = ::PaletteSize((LPSTR)lpDIB); //调色板尺寸
HANDLE dibNew = ::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
LPSTR lpDIBNew = (LPSTR) ::GlobalLock(dibNew);
::memcpy((unsigned char*)lpDIBNew, (unsigned char*)lpDIB, sizeof(BITMAPINFOHEADER) + palSize );
unsigned char *lpDIBBitsNew = (unsigned char *)::FindDIBBits(lpDIBNew);
MatrixXd b1, b2;
MatrixXd X=MatrixXd::Zero(7, 6);
MatrixXd Y1= MatrixXd::Zero(7, 1);
MatrixXd Y2 = MatrixXd::Zero(7, 1);
if (pointVec.size() == 14) {
for (int i = 0;i < 7;++i) {
CPoint point = pointVec[i];
point.y = height - point.y;
X(i, 0) = 1;
X(i, 1) = point.x;
X(i, 2) = point.y;
X(i, 3) = point.x*point.x;
X(i, 4) = point.y*point.y;
X(i, 5) = point.x*point.y;
}
for (int i = 7;i < 14;++i) {
CPoint point = pointVec[i];
point.y = height - point.y;
Y1(i - 7, 0) = point.x;
Y2(i - 7, 0) = point.y;
}
}
MatrixXd tmp = (X.transpose()*X).inverse();
b1 =tmp*X.transpose()*Y1;
b2 = tmp * X.transpose()*Y2;
CString string;
pointVec.clear();
string.Format("k100:%3f,k110:%3f,k101:%f,k120:%3f,k102:%3f,k111:%3f\nk200:%3f,k210:%3f,k201:%3f,k220:%3f,k202:%3f,k221:%3f",
b1(0,0), b1(1, 0), b1(2, 0), b1(3, 0), b1(4, 0), b1(5, 0), b2(0, 0), b2(1, 0), b2(2, 0), b2(3, 0), b2(4, 0), b2(5, 0) );
::MessageBox(0,string, "dataMessage", MB_OKCANCEL);
for (int i = 0;i < height;++i) {
for (int j = 0;j < width;++j) {
for (int z = 0;z < biBitCount;++z) {
*(lpDIBBitsNew + i * lineByte + j * biBitCount + z) = 0;
}
}
}
for (int i = 0;i < height;++i) {
for (int j = 0;j < width;++j) {
tmpdata(0, 0) = 1;
tmpdata(0, 1) = j;
tmpdata(0, 2) = i;
tmpdata(0, 3) = j*j;
tmpdata(0, 4) = i*i;
tmpdata(0, 5) = i*j;
float xnum = (tmpdata * b1).determinant();
float ynum = (tmpdata * b2).determinant();
int xint = (int)xnum;
int yint = (int)ynum;
for (int z = 0;z < biBitCount;++z) {
if (xnum >= 0 && xnum < width&&ynum >= 0 && ynum <= height) {
if (xnum >= 1 && xnum < width - 1 && ynum >= 1 && ynum <= height - 1)
*(lpDIBBitsNew + i * lineByte + j * biBitCount + z) = *(lpDIBBits + yint * lineByte + xint * biBitCount + z)
+ (*(lpDIBBits + (yint + 1) * lineByte + xint * biBitCount + z) - *(lpDIBBits + yint * lineByte + xint * biBitCount + z))*(ynum - yint)
+ (*(lpDIBBits + yint * lineByte + (xint + 1) * biBitCount + z) - *(lpDIBBits + yint * lineByte + xint * biBitCount + z))*(xnum - xint)
+ (*(lpDIBBits + (yint + 1) * lineByte + (xint + 1) * biBitCount + z) + *(lpDIBBits + yint * lineByte + xint * biBitCount + z)
- *(lpDIBBits + (yint + 1) * lineByte + xint * biBitCount + z) - *(lpDIBBits + yint * lineByte + (xint + 1) * biBitCount + z))*(xnum - xint)*(ynum - yint);
else
*(lpDIBBitsNew + i * lineByte + j * biBitCount + z) = *(lpDIBBits + yint * lineByte + xint * biBitCount + z);
}
}
}
}
::GlobalUnlock(dib);
::GlobalUnlock(dibNew);
CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
CDemoView* pView = (CDemoView*)pFrame->MDIGetActive()->GetActiveView();
CDemoDoc* pDocNew = pView->GetDocument();
pDocNew->ReplaceHDIB((HDIB)dibNew);
pDocNew->InitDIBData();
pDocNew->UpdateAllViews(pView);
Invalidate();
}
大津阈值分割:最大方差分割:
代码如下:
void CDemoView::OnOtsuthresholdsegmentation()
{
// TODO: 在此添加命令处理程序代码
CDemoDoc *pDoc = GetDocument();
HDIB dib = pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)dib);
int width = ::DIBWidth(lpDIB);
int height = ::DIBHeight(lpDIB);
LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB;
int biBitCount = phead->biBitCount / 8;
if (biBitCount != 1)
{
::MessageBox(0, "ERROR!NOT GRAY LEVEL IMAGE!", NULL, MB_OK);
::GlobalUnlock(dib);
return;
}
int lineByte = (width * biBitCount + 3) / 4 * 4;
unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB);
int palSize = ::PaletteSize((LPSTR)lpDIB); //调色板尺寸
HANDLE dibNew = ::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
LPSTR lpDIBNew = (LPSTR) ::GlobalLock(dibNew);
::memcpy((unsigned char*)lpDIBNew, (unsigned char*)lpDIB, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
unsigned char *lpDIBBitsNew = (unsigned char *)::FindDIBBits(lpDIBNew);
int max = 0;
int min = 255;
int data;
int i, j;
double pix[256];
int sumpix = height * width;
for (i = 0;i < 256;++i) {
pix[i] = 0;
}
for (i = 0;i < height;i++) {
for (j = 0;j < width;j++) {
data = *(lpDIBBits + i * lineByte + j);
pix[data]++;
}
}
for (i = 0;i < 256;++i) {
pix[i] = pix[i] / sumpix;
}
double SquErr[256];
for (int i = 0;i < 256;++i) { //T=i 为阈值
double w0 = 0, w1 = 0;
double u0 = 0, u1 = 0;
for (j = 0;j < i;++j) {
w0 = w0 + pix[j];
u0 =u0+ j * pix[j];
}
if(w0!=0)
u0 = u0 / w0;
w1 = 1 - w0;
for (j = i;j < 256;++j) {
u1 =u1 +j * pix[j];
}
if(w1!=0)
u1 = u1 / w1;
SquErr[i] = w0 * w1*(u1 - u0)*(u1 - u0);
}
int maxpos=0;
double maxerr = SquErr[0];
for (i = 0;i < 256;++i) { //求最大方差
if (maxerr < SquErr[i]) {
maxpos = i;
maxerr = SquErr[i];
}
}
for (i = 0;i < height;i++) {
for (j = 0;j < width;j++) {
if(*(lpDIBBits + i * lineByte + j)m_pMainWnd);
pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
CDemoView* pView = (CDemoView*)pFrame->MDIGetActive()->GetActiveView();
CDemoDoc* pDocNew = pView->GetDocument();
pDocNew->ReplaceHDIB((HDIB)dibNew);
pDocNew->InitDIBData();
pDocNew->UpdateAllViews(pView);
Invalidate();
}
还有图像压缩的一些东西,下次再写