{Emgu}{C#}保存圖片、視頻等


一、簡介

以前研究所的時候,有使用VC.NET 配合 OpenCV 做影像處理,這東西相當讚,可以省去不少開發時間,今天嘗試看看如何在Visual C# 2008 上使用 OpenCV。

以下引用 OpenCV 中文網站 的介紹

1. 什麼是OpenCV
OpenCV是Intel®開源電腦視覺庫。它由一系列 C 函數和少量 C++ 類構成,實現了圖像處理和電腦視覺方面的很多通用演算法。

2. OpenCV 重要特性
OpenCV 擁有包括 300 多個C函數的跨平臺的中、高層 API。它不依賴於其它的外部庫——儘管也可以使用某些外部庫。
OpenCV 對非商業應用和商業應用都是免費(FREE)的。(細節參考license)。
OpenCV 為Intel®Integrated Performance Primitives (IPP) 提供了透明介面。這意味著如果有為特定處理器優化的的 IPP 庫, OpenCV 將在運行時自動載入這些庫。 更多關於 IPP 的信息請參考: http://www.intel.com/software/products/ipp/index.htm

3. 體驗OpenCV 的魅力

看了以上對OpenCV的介紹,還是不知道OpenCV在做什麼的話,可以先看這段影片,影片的成果是透過 OpenCV 所撰寫而成。 

 

二、方法

1. 下載與安裝OpenCV

要使用 OpenCV,首先必須要下載並且安裝,點這裡下載 OpenCV_1.1pre1a.exe,下載後執行安裝,安裝過程幾乎都是點選下一步,在此需記住安裝目錄為何,預設為 C:\Program Files\OpenCV。

 

  

2. 下載與安裝EmguCV

EmguCV 封裝了 OpenCV image processing library,而且可在.Net平台使用,因此在本文中,透過EmguCV,讓我們可以在 Visual C# 2008 中使用OpenCV。

點選這裡下載Emgu.CV.Binary-1.5.0.1.zip,下載完成後,解壓縮檔案可看EmguCV的DLL檔;我將此目錄放到 C:\Program Files\OpenCV,解壓縮後的檔案只要自己記得就好,因為之後要將這些檔案加入參考。

(1) 下載網頁部份

 

 

 

(2) 下載後解壓縮檔案

 

3. 新增專案,並且加入相關的參考

先 [ 新增專案 ] -> [ Visual C# ]-> [ WIndows Form 應用程式 ],接著將上個步驟中的 dll加入參考,要加入的參考請參考下圖。

 

4. 加入 EmguCV的控制項,到工具箱中

主要是將 Emgu.CV.UI.dll加入工具箱中,加入後會出現 ImageBoxHistogramCtrl

 

 

5. 到此,已經將要撰寫OpenCV的工作完成了。開始撰寫程式碼,在這裡示範兩個範例,第一個是開啟並顯示 WebCam 畫面。

5.1 先在Form上拉兩個控制項,分別是Button ( Name : captureButton )與 ImageBox ( Name : captureImageBox )

 

5.2 撰寫以下程式碼

01 using System;
02 usingSystem.Collections.Generic;
03 usingSystem.ComponentModel;
04 using System.Data;
05 using System.Drawing;
06 using System.Linq;
07 using System.Text;
08 using System.Windows.Forms;
09
10 // 要引用的類別
11 using Emgu.CV;
12 using Emgu.CV.Structure;
13 using Emgu.Util;
14 using System.Threading;
15
16 namespace MyOpenCV
17 {
18     public partial class Form2 :Form
19     {
20         public Form2()
21         {
22             InitializeComponent();
23         }
24
25         private Capture_capture;
26         private bool_captureInProgress;
27
28         private voidProcessFrame(object sender, EventArgs arg)
29         {
30             Image<Bgr,Byte> frame = _capture.QueryFrame();  
31             captureImageBox.Image= frame;
32         }
33
34         private voidcaptureButton_Click(object sender, EventArgs e)
35         {
36             if capture is not created, create it now
49
50             if (_capture!= null)
51             {
52                 if(_captureInProgress)
53                 {  //stop thecapture
54                     Application.Idle-= new EventHandler(ProcessFrame);
55                     captureButton.Text= "Start Capture";
56                 }
57                 else
58                 {
59                     //start thecapture
60                     captureButton.Text= "Stop";
61                     Application.Idle+= new EventHandler(ProcessFrame);
62                 }
63
64                 _captureInProgress= !_captureInProgress;
65             }
66         }
67     }
68 }

 

5.3 執行結果,請注意喔,以下顯示的是 Webcam 即時視訊,不是影像喔

 

6. 第二個範例,我們將上一個範例,加上灰階、Canny處理

讓大家了解 OpenCV 的強大,而這動作,只需要多拉兩個ImageBox在加上幾行程式就可以了喔,真是太讚了,難怪很多學生想畢業,都用OpenCV

6.1 在上一個範例中,在多拉兩個 ImageBox,Name 分別為grayscaleImageBox、cannyImageBox

 

6.2 將上一個範例,加上四行程式碼就可以達成將Webcam視訊灰階以及Canny

 

01 using System;
02 usingSystem.Collections.Generic;
03 usingSystem.ComponentModel;
04 using System.Data;
05 using System.Drawing;
06 using System.Linq;
07 using System.Text;
08 using System.Windows.Forms;
09
10 // 要引用的類別
11 using Emgu.CV;
12 using Emgu.CV.Structure;
13 using Emgu.Util;
14 using System.Threading;
15
16 namespace MyOpenCV
17 {
18     public partial class Form2 :Form
19     {
20         public Form2()
21         {
22             InitializeComponent();
23         }
24
25         private Capture_capture;
26         private bool_captureInProgress;
27
28         private voidProcessFrame(object sender, EventArgs arg)
29         {
30             Image<Bgr,Byte> frame = _capture.QueryFrame();  
31             captureImageBox.Image= frame;
32
33             // 請再加上以下四行程式碼
34             Image<Gray,Byte> grayFrame = frame.Convert<Gray, Byte>();
35             Image<Gray,Byte> cannyFrame = grayFrame.Canny(new Gray(100), new Gray(60));
36             grayscaleImageBox.Image= grayFrame;
37             cannyImageBox.Image= cannyFrame;
38         }
39
40         private voidcaptureButton_Click(object sender, EventArgs e)
41         {
42             if capture is not created, create it now
55
56             if (_capture!= null)
57             {
58                 if(_captureInProgress)
59                 {  //stop thecapture
60                     Application.Idle-= new EventHandler(ProcessFrame);
61                     captureButton.Text= "Start Capture";
62                 }
63                 else
64                 {
65                     //start thecapture
66                     captureButton.Text= "Stop";
67                     Application.Idle+= new EventHandler(ProcessFrame);
68                 }
69
70                 _captureInProgress= !_captureInProgress;
71             }
72         }
73     }
74 }

 

6.3 執行結果

 

三、範例下載

 http://cid-101d8ba47227b414.skydrive.live.com/self.aspx/.Public/MyOpenCV.rar

 

四、遇到錯誤 'Emgu.CV.CvInvoke' 的型別初始設定式發生例外狀況

1. 將您的 OpenCV 資料夾路徑與 Emgu 資料夾路徑加入Windows 環境變數。

2. 使用 Visual Studio 開啟您的專案。

    (1) 在專案上按滑鼠右鍵,選擇 [屬性] / [參考路徑],加入你的 OpenCV 與 Emgu 的安裝路徑。

    (2) 在建置組態中,把平台改成 X86,參考 HOW TO:將專案設定成以平台為目標


轉自:http://www.dotblogs.com.tw/chou/archive/2009/06/13/8812.aspx

 

 

http://www.cnblogs.com/maiye/archive/2010/06/19/1761075.html

首先介紹一下自己的情況,2010年的3月份開始接觸學習C#編程,之前C#和OpenCV都是零基礎,由於全都是自學進度比較慢,中間也走了不少 彎路。進過三個月自己的學習與探索,對C#中使用OpenCV也算是有點心得,希望對初學者有所幫助,也希望大牛們進行指點。我使用的編程環境是 VS2005,使用的Emgucv 2.1.0.793版本。

1.先是在程序中圖像的導入,我是根據圖像路徑實現,其中path是string類型,是圖像路徑。

IntPtr img=CvInvoke.cvLoadImage(path, Emgu.CV.CvEnum.LOAD_IMAGE_TYPE.CV_LOAD_IMAGE_ANYCOLOR);

2.圖像灰度化處理,先創建一幅尺寸大小為為原圖的8位圖像GrayImg1:

Rectangle cr = CvInvoke.cvGetImageROI(img1);

                int width = cr.Width;

                int height = cr.Height;

IntPtr GrayImg1 = CvInvoke.cvCreateImage(cr.Size, Emgu.CV.CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 1);

現在就能使用cvCvtColor函數實現灰度化:

CvInvoke.cvCvtColor(img1, GrayImg1, Emgu.CV.CvEnum.COLOR_CONVERSION.CV_BGR2GRAY);

3.直方圖的創建,並獲取數據

int[] hist_size = new int[1] { 256 };//建一個數組來存放直方圖數據

IntPtr HistImg=CvInvoke.cvCreateHist(1, hist_size, Emgu.CV.CvEnum.HIST_TYPE.CV_HIST_ARRAY, null, 1);//創建了一個空的直方圖

CvInvoke.cvCalcHist(inPtr1, HistImg,false,System.IntPtr.Zero);//計算inPtr1指向圖像的數據,並傳入Histimg中,其中 IntPtr[] inPtr1 = new IntPtr[1] { SubImg}。

現在要獲取Histimg中的具體數據:

for (int i = 0; i < 256; i++)

            {

                temphist[i] = CvInvoke.cvQueryHistValue_1D(histImg, i);

            }

這樣在數組temphist中保存了直方圖數據。

4.對第一步中由cvLoadImage導入的圖像進行像素點的操作。由於img 是IntPtr類型無法直接進行操作,所以首先要進行格式的轉化,把IntPtr型轉換成MIplImage:

Emgu.CV.Structure.MIplImage MIpImg =

(Emgu.CV.Structure.MIplImage)System.Runtime.InteropServices.Marshal.PtrToStructure(img, typeof(Emgu.CV.Structure.MIplImage));

然后再C#中使用unsafe中指針操作:npixel = (int)((byte*)img.imageData + img.widthStep * i)[j];

5.在二值話的圖像,對不為零的區域經行檢測。

IntPtr Dyncontour = new IntPtr();//存放檢測到的圖像塊的首地址

IntPtr Dynstorage = CvInvoke.cvCreateMemStorage(0);開辟內存區域

int n= CvInvoke.cvFindContours(tempimg, Dynstorage, ref Dyncontour, StructSize.MCvContour, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_CCOMP,Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE, new Point(0, 0));

n表示檢測到不為零區域的個數。

6.對第五步檢測到的區域繪制輪廓

for(;DyncontourTemp!=null&&DyncontourTemp.Ptr.ToInt32()!=0;DyncontourTemp=DyncontourTemp.HNext)

{

CvInvoke.cvDrawContours(tempContImg, DyncontourTemp,new MCvScalar(255, 255, 255),new MCvScalar(255, 255, 255), 0, 1, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, new Point(0, 0));

 }

其中的DyncontourTemp為

Seq<Point> DyncontourTemp1= new Seq<Point>(Dyncontour, null);//方便對IntPtr類型進行操作

Seq<Point> DyncontourTemp=DyncontourTemp1;

7.對第五步檢測出的區域的坐標提取,通過cvFindContours函數的調用在 Dyncontour中存放的是不為零區域坐標的值存儲在內存中的首地址指針。

seq<Point> DyncontourTemp1= new Seq<Point>(Dyncontour, null); //方便對IntPtr類型進行操作

int total=contourImg.Total;//contourImg包含的元素的總數

 int TempX = 0;  int TempY = 0;int[,] contourArray = new int[2,total];

 //獲得輪廓的坐標值

 for (int i = 0; i < total;i++ )

{

  contourArray[0,i]=contourImg[i].X;

  contourArray[1,i]=contourImg[i].Y;

 }

 

                                                C#下用OPENCV的配置OPENCV

下面是EMGUCV的使用方法:

一 首先下載EmguCV,就是可以在Visual Studio2005/2008中引用OpenCV的函數的dll庫。可以到這里下載:http://groups.google.com/group/tim-files/files?upload=1     名為"Emgu.CV.Windows.Binary-1.3.0.0.zip"
二 將文件解壓出來,放到哪里都可以,不過建議將解壓出來的文件夾放到OpenCV的目錄下面,這樣不會誤刪吧,呵呵。
三 當然,在用EmguCV之前,要安裝了OpenCV,並且OpenCV的各項配置都配置OK了,我這里說的只是配置EmguCV的。所以,請確保在配置 EmguCV之前你的OpenCV的開發環境已經配置OK了。如果不會,可以看我的一篇文章。就在"學海泛舟篇"中,找找看吧。
四 打開Visual Studio 2005/2008,新建C#的Win32窗體應用程序。然后,點擊"項目"-〉"添加引用"-〉"瀏覽",然后把EmguCV1.3.0目錄下的 Emgu.CV.dll Emgu.Util.dll ZedGraph.dll zlib.net.dll 都添加到引用里面,其實也不用全部添加,不過由於我們不知道有些函數在那些dll中,所以索性全添加就可以了。
五 然后,再程序的開頭中加上 using Emgu.CV; using Emgu.Util; 之后就可以用EmguCV中所有的庫函數了。
六 在窗體上畫一個按鈕,然后再按紐的下面寫上如下的程序:
private void btnOpenImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvNamedWindow("打開圖片");
                IntPtr img = CvInvoke.cvLoadImage(openFileDialog.FileName, Emgu.CV.CvEnum.LOAD_IMAGE_TYPE.CV_LOAD_IMAGE_UNCHANGED);
                CvInvoke.cvShowImage("打開圖片", img);
                this.img = img;
                CvInvoke.cvWaitKey(0);
                CvInvoke.cvReleaseImage(ref img);
                CvInvoke.cvDestroyWindow("打開圖片");
            }
        }
這樣,我們就能用OpenCv的函數來打開和顯示一個圖片了。如果要保存圖片可以如下:
private void btnSaveImage_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvSaveImage(saveFileDialog.FileName, this.img);
            }
        }
如果要打開一個AVI視頻文件,可以如下:
private void btnOpenAVI_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "AVI文件|*.avi";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvNamedWindow("打開視頻");
                IntPtr capture=CvInvoke.cvCreateFileCapture(openFileDialog.FileName);
                this.video = capture;
                IntPtr frame = new IntPtr();
                while (true)
                {
                    frame = CvInvoke.cvQueryFrame(capture);
                    CvInvoke.cvShowImage("打開視頻", frame);
                    //if (!frame) break;
                    int c = CvInvoke.cvWaitKey(20);
                    if (c == 13) break;
                }
                //this.video = capture;
                CvInvoke.cvWaitKey(0);
                CvInvoke.cvReleaseCapture(ref capture);
                CvInvoke.cvDestroyWindow("打開視頻");
            }
        }
要保存一個AVI文件可以如下:
private void btnSaveAVI_Click(object sender, EventArgs e)
        {
            IntPtr avi = this.video;
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                IntPtr videoWriter = CvInvoke.cvCreateVideoWriter(saveFileDialog.FileName, -1, 20, new Emgu.CV.MCvSize(480, 500), 1);
                IntPtr capture=CvInvoke.cvCreateFileCapture(saveFileDialog.FileName);
                IntPtr frame = new IntPtr();
                while (true)
                {
                    frame = CvInvoke.cvQueryFrame(capture);
                    CvInvoke.cvWriteFrame(videoWriter, frame);
                }
            }
        }
注意上面的保存AVI和打開AVI文件還存在問題:就是在AVI文件結尾處,如何退出的問題。在C++里面我們可以用if(!frame) break;來退出。但是在C#中這樣是不行的,因為在C#中圖片的類型是IntPtr類型。所以,在打開AVI文件的程序中,我用了 cvWaitKey()的返回值來退出播放AVI文件。而在保存中沒有設置什么時候保存完畢,所以,保存AVI文件會出現問題。不過,只是提供了一種思路 罷了。

 

Opencv C# 學習之一 打開圖片

 

http://blog.sina.com.cn/s/blog_6174faf60100gg7u.html

在C#中寫一段代碼,打開一副圖像並顯示出來。

1、新建一個C#工程;

2、程序的開頭中加上 using Emgu.CV; using Emgu.Util;

3、在窗體上畫一個按鈕,然后再按紐的下面寫上如下的程序:

private void btnOpenImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvNamedWindow("打開圖片");
                IntPtr img = CvInvoke.cvLoadImage(openFileDialog.FileName, Emgu.CV.CvEnum.LOAD_IMAGE_TYPE.CV_LOAD_IMAGE_UNCHANGED);
                CvInvoke.cvShowImage("打開圖片", img);
                this.img = img;
                CvInvoke.cvWaitKey(0);
                CvInvoke.cvReleaseImage(ref img);
                CvInvoke.cvDestroyWindow("打開圖片");
            }
        }

 

Emgu CV學習之二 保存圖片

http://blog.sina.com.cn/s/blog_6174faf60100gg7w.html

我們學會了打開圖片,如果要保存圖片,也很簡單:

創建一根按鈕控件,命名為btnSaveImage;然后添加如下代碼:

private void btnSaveImage_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvSaveImage(saveFileDialog.FileName, this.img);
            }
        }

 

OpenCV學習之三 打開視頻文件

http://blog.sina.com.cn/s/blog_6174faf60100gg80.html

創建一根按鈕並命名為btnOpenAVI:

雙擊按鈕並添加如下代碼:

 

private void btnOpenAVI_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "AVI文件|*.avi";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                CvInvoke.cvNamedWindow("打開視頻");
                IntPtr capture=CvInvoke.cvCreateFileCapture(openFileDialog.FileName);
                this.video = capture;
                IntPtr frame = new IntPtr();
                while (true)
                {
                    frame = CvInvoke.cvQueryFrame(capture);
                    CvInvoke.cvShowImage("打開視頻", frame);
                    //if (!frame) break;
                    int c = CvInvoke.cvWaitKey(20);
                    if (c == 13) break;
                }
                //this.video = capture;
                CvInvoke.cvWaitKey(0);
                CvInvoke.cvReleaseCapture(ref capture);
                CvInvoke.cvDestroyWindow("打開視頻");
            }
        }

 

OpenCV學習之四:保存視頻文件

http://blog.sina.com.cn/s/blog_6174faf60100gg83.html

private void btnSaveAVI_Click(object sender, EventArgs e)
        {
            IntPtr avi = this.video;
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "BMP文件|*.bmp|JPG文件|*.jpg|JPEG文件|*.jpeg|所有文件|*.*";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
               // IntPtr videoWriter = CvInvoke.cvCreateVideoWriter(saveFileDialog.FileName, -1, 20, new Emgu.CV.MCvSize(480, 500), 1);

                  VideoWriter videoWriter = new VideoWriter(saveFileDialog.FileName,20,640,480,true);
                IntPtr capture=CvInvoke.cvCreateFileCapture(saveFileDialog.FileName);
                IntPtr frame = new IntPtr();
                while (true)
                {
                    frame = CvInvoke.cvQueryFrame(capture);
                    videoWriter.WriteFrame <Bgr,Byte>(frame);               }
            }
        }

 

這個保存程序還有點問題。

 

【OpenCV】打開攝像頭 保存視頻文件(轉)

http://blog.sina.com.cn/s/blog_6174faf60100ghng.html

OpenCV】打開攝像頭 保存視頻文件
 

 

作者:彭軍

這個程序首先打開攝像頭,然后保存攝像頭所拍攝的內容。需要注意的就是在保存視頻時編碼器的選擇,最好用默認的就OK了,就是選壓縮程序選擇Cinepak Codec by Radius. 壓縮質量可以根據自己的需要選擇大小。具體程序如下:

#include "cv.h"

#include "highgui.h"

#include "iostream.h"

int main()

{

CvCapture* capture=cvCaptureFromCAM(-1);

CvVideoWriter* video=NULL;

IplImage* frame=NULL;

int n;

if(!capture) //如果不能打開攝像頭給出警告

{

cout<<"Can not open the camera."<<endl;

return -1;

}

else

{

frame=cvQueryFrame(capture); //首先取得攝像頭中的一幀

video=cvCreateVideoWriter("camera.avi",-1,32,

cvSize(frame->width,frame->height)); //創建CvVideoWriter對象並分配空間

//保存的文件名為camera.avi,編碼要在運行程序時選擇,大小就是攝像頭視頻的大小,幀頻率是32

if(video) //如果能創建CvVideoWriter對象則表明成功

{

cout<<"VideoWriter has created."<<endl;

}

cvNamedWindow("Camera Video",1); //新建一個窗口

while(1)

{

frame=cvQueryFrame(capture); //從CvCapture中獲得一幀

if(!frame)

{

cout<<"Can not get frame from the capture."<<endl;

break;

}

n=cvWriteFrame(video,frame); //判斷是否寫入成功,如果返回的是1,表示寫入成功

cout<<n<<endl;

cvShowImage("Camera Video",frame); //顯示視頻內容的圖片

if(cvWaitKey(2)>0) break; //有其他鍵盤響應,則退出

}

cvReleaseVideoWriter(&video);

cvReleaseCapture(&capture);

cvDestroyWindow("Camera Video");

}

return 0;

 

直方圖均衡化的算法和代碼

http://blog.sina.com.cn/s/blog_6174faf60100gra0.html

直方圖均衡化算法分為三個步驟,第一步是統計直方圖每個灰度級出現的次數,第二步是累計歸一化的直方圖,第三步是計算新的像素值。

第一步:

    for(i=0;i<height;i++){
      for(j=0;j<width;j++){
           n[s[i][j]]++;
       }
    }

    for(i=0;i<L;i++){

        p[i]=n[i]/(width*height);

    }

    這里,n[i]表示的是灰度級為i的像素的個數,L表示的是最大灰度級,width和height分別表示的是原始圖像的寬度和高度,所以,p[i]表示的就是灰度級為i的像素在整幅圖像中出現的概率(其實就是p[]這個數組存儲的就是這幅圖像的歸一化之后的直方圖)。

第二步:

    for(i=0;i<=L;i++){
      for(j=0;j<=i;j++){
           c[i]+=p[j];
       }
    }

    c[]這個數組存儲的就是累計的歸一化直方圖。

第三步:

    max=min=s[0][0];
    for(i=0;i<height;i++){
        for(j=0;j<width;j++){
           if(max<s[i][j]){

               max=s[i][j];

           }else if(min>s[i][j]){

               min=s[i][j];

           }
       }
    }

    找出像素的最大值和最小值。

    for(i=0;i<height;i++){
      for(j=0;j<width;j++){
           t[i][j]=c[s[i][j]]*(max-min)+min;
      }
    }

    t[][]就是最終直方圖均衡化之后的結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM