1. 程式人生 > >【程式語言】利用CImage類對影象畫素的處理(影象二值化)

【程式語言】利用CImage類對影象畫素的處理(影象二值化)

    最近做的課程作業需要用到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");
}

                                                原圖

                                 二值化