【程式語言】利用CImage類對影象畫素的處理(影象二值化)
阿新 • • 發佈:2019-02-03
最近做的課程作業需要用到CImage函式處理影象,其中涉及到讀取影象以及對影象畫素進行操作,在這裡記錄一下自己的理解。
首先是CImage類的定義和讀取圖片
CImage srcImage;
CImage dstImage;
CString path = "C:\\Users\\Administrator\\Desktop\\閾值分割_20172120658\\input.png";
CString pathdown = "C:\\Users\\Administrator\\Desktop\\閾值分割_20172120658\\outtput.png";
如圖 定義兩個CImage類的物件,然後使用CString型別的變數定義圖片的讀取路徑和儲存路徑。
srcImage.Load(path);
byte* pRealData;
這裡利用CImage::Load()函式讀取圖片到srcImage中,接下來準備讀取影象中的畫素值,因為在CImage中利用堆疊進行讀取的方法速度很慢,在這裡我就不寫了,這裡使用的是直接利用c裡面的指標對畫素進行讀取和遍歷操作。首先定義一個byte型別的指標。
pRealData = (byte*)srcImage.GetBits(); //獲取到圖片記憶體點的位置 int pit = srcImage.GetPitch(); //影象每行位元組數 int bitCount = srcImage.GetBPP() / 8; //獲取每畫素的位數~~/8得到位元組數 cout << "影象每行的位元組數" << pit << " " << "影象每個畫素的位數" << bitCount << endl;
利用CImage::GetBits()函式獲取圖片記憶體點的位置,使用這種方法的時候,需要考慮圖形的結構,使用CImage::GetBPP獲取每個畫素點佔幾位,還需要使用CImage::GetPitch獲取每一行位的個數,根據GetPitch的正負值來判定GetBits獲取到的head是首行的還是尾行的。負值即為尾部,正值即為頭部。
其中pit得到的是位元組數,也就是說如果每個畫素有3個位元組(RGB),一個寬為100畫素的圖片它的CImage::GetPitch()就是300。CImage::GetBPP()得到的是每個畫素的位數,通常灰度圖為8或者32,三通道RGB影象為24位。
int height = srcImage.GetHeight();
int width = srcImage.GetWidth();
cout << "height" << height << " width" << width << endl;
vector<int> gray(256);
for (int i = 1; i <= 256; i++)
{
gray.push_back(0);
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
gray.at((int)(*(pRealData + pit*i + j*bitCount))) += 1;
}
}
對影象的畫素進行讀取,需要對指標進行轉換,轉換為int型別。我這裡是對影象的灰度值進行了統計處理。
最後附上一個利用直方圖做的影象二值化
#include<atlimage.h>
#include<stdio.h>
#include<iostream>
#include<vector>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
void main()
{
CImage srcImage;
CImage dstImage;
CString path = "C:\\Users\\Administrator\\Desktop\\閾值分割_20172120658\\input.png";
CString pathdown = "C:\\Users\\Administrator\\Desktop\\閾值分割_20172120658\\outtput.png";
srcImage.Load(path);
byte* pRealData;
byte* pRealData1;
byte* pRealData2;
byte* pRealData3;
pRealData = (byte*)srcImage.GetBits(); //獲取到圖片記憶體點的位置
int pit = srcImage.GetPitch(); //影象每行位元組數
int bitCount = srcImage.GetBPP() / 8; //獲取每畫素的位數~~/8得到位元組數
cout << "影象每行的位元組數" << pit << " " << "影象每個畫素的位數" << bitCount << endl;
int height = srcImage.GetHeight();
int width = srcImage.GetWidth();
cout << "height" << height << " width" << width << endl;
vector<int> gray(256);
for (int i = 1; i <= 256; i++)
{
gray.push_back(0);
}
//pRealData1 = pRealData;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
gray.at((int)(*(pRealData + pit*i + j*bitCount))) += 1;
}
}
int max = 0;
int sec = 0;
int locamax = 0;
int locasec = 0;
for (int i = 0; i < 256; i++)
{
cout << i << "---" << gray[i] << endl;
if (gray[i] > max)
{
max = gray[i];
locamax = i; //獲取相同灰度值畫素點最多的灰度值
}
}
for (int i = 0; i < 256; i++)
{
if (gray[i] > sec&&abs(i-locamax)>10) //第二多的點需要距離最多的點至少10個灰度單位
{
sec = gray[i];
locasec = i; //獲取相同灰度值畫素點第二多的灰度值
}
}
cout <<locamax<<"__"<<locasec << endl;
int min = (locamax + locasec) / 2; //取兩峰中間值作為二值化分割閾值
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if ((int)(*(pRealData + pit*i + j*bitCount)) < min)
{
*(pRealData + pit*i + j*bitCount) = 0;
*(pRealData + pit*i + j*bitCount+1) = 0;
*(pRealData + pit*i + j*bitCount+2) = 0;
}
else
{
*(pRealData + pit*i + j*bitCount) = 255;
*(pRealData + pit*i + j*bitCount + 1) = 255;
*(pRealData + pit*i + j*bitCount + 2) = 255;
}
}
}
srcImage.Save(pathdown);
system("pause");
}
原圖
二值化