GDAL算法进度条使用说明
? ? 在調用GDAL算法的時候,希望能夠顯示其處理進度信息,其實在GDAL的算法API中,一般最后兩個參數就是進度信息的指針。下面分別實現兩種進度條信息,一種是在控制臺中的進度條,一種是基于QT界面的進度條(你可以參考寫一個MFC的)。
? ? 對于GDAL來說,本身就實現了一個基于控制臺的進度條函數,名字叫GDALTermProgress,其函數說明參考這里?,調用這個進度函數后,會在控制臺中顯示一個進度信息,形狀大概就是下面的樣子:
0...10...20...30...40...50...60...70...80...90...100 - done. ? ? 每個2.5%就會輸出一個點,然后每到10%就會輸出數字,在完成結束后會輸出done。? ? GDAL的算法中,一般最后兩個參數是用來返回進度信息的,下面以柵格矢量化的接口舉例說明,GDAL柵格矢量化的函數接口定義為:
| CPLErr GDALPolygonize | ( | GDALRasterBandH? | hSrcBand, | |
| ? | ? | GDALRasterBandH? | hMaskBand, | |
| ? | ? | OGRLayerH? | hOutLayer, | |
| ? | ? | int? | iPixValField, | |
| ? | ? | char **? | papszOptions, | |
| ? | ? | GDALProgressFunc? | pfnProgress, | |
| ? | ? | void *? | pProgressArg | ? |
| ? | ) |
? ? 算法說明文檔參考地址:http://www.gdal.org/gdal__alg_8h.html#a3f522a9035d3512b5d414fb4752671b1。從文檔中可以看到,最后兩個參數說明是:
| pfnProgress? | callback for reporting algorithm progress matching the?GDALProgressFunc()?semantics. May be NULL. | |
| pProgressArg? | callback argument passed to pfnProgress. | ? |
? ??該回調函數參數說明分別是:
| ? | dfComplete? | 進度值,取值范圍是0.0~1.0,0.0表示開始,1.0表示完成。 |
| ? | pszMessage? | 可選項,用來顯示的字符串信息。通常用NULL即可。 |
| ? | pProgressArg? | 應用程序回調函數參數,是一個自定義的類(或結構體)指針。 |
/** * @brief 進度條基類 * * 提供進度條基類接口,來反映當前算法的進度值 */ class IMGALG_API CProcessBase { public:/*** @brief 構造函數*/CProcessBase() {m_dPosition = 0.0;m_iStepCount = 100;m_iCurStep = 0;m_bIsContinue = true;}/*** @brief 析構函數*/virtual ~CProcessBase() {}/*** @brief 設置進度信息* @param pszMsg 進度信息*/virtual void SetMessage(const char* pszMsg) = 0;/*** @brief 設置進度值* @param dPosition 進度值* @return 返回是否取消的狀態,true為不取消,false為取消*/virtual bool SetPosition(double dPosition) = 0;/*** @brief 進度條前進一步,返回true表示繼續,false表示取消* @return 返回是否取消的狀態,true為不取消,false為取消*/virtual bool StepIt() = 0;/*** @brief 設置進度個數* @param iStepCount 進度個數*/virtual void SetStepCount(int iStepCount){ReSetProcess(); m_iStepCount = iStepCount;}/*** @brief 獲取進度信息* @return 返回當前進度信息*/string GetMessage(){return m_strMessage;}/*** @brief 獲取進度值* @return 返回當前進度值*/double GetPosition(){return m_dPosition;}/*** @brief 重置進度條*/void ReSetProcess(){m_dPosition = 0.0;m_iStepCount = 100;m_iCurStep = 0;m_bIsContinue = true;}/*! 進度信息 */string m_strMessage;/*! 進度值 */double m_dPosition; /*! 進度個數 */int m_iStepCount; /*! 進度當前個數 */int m_iCurStep; /*! 是否取消,值為false時表示計算取消 */bool m_bIsContinue; }; ? ? 該類是一個進度條基類,將一些通用的函數進行實現,比如獲取進度值,獲取進度信息等之類的,然后將一些需要根據使用方式不同的設置為虛函數,比如設置進度值等。下面給出一個控制臺進度條類,用于顯示基于控制臺程序的進度值顯示,參考GDALTermProgress函數寫的:/** * @brief 控制臺進度條類 * * 提供控制臺程序的進度條類接口,來反映當前算法的進度值 */ class CConsoleProcess : public CProcessBase { public:/*** @brief 構造函數*/CConsoleProcess() {m_dPosition = 0.0;m_iStepCount = 100;m_iCurStep = 0;};/*** @brief 析構函數*/~CConsoleProcess() {//remove(m_pszFile);};/*** @brief 設置進度信息* @param pszMsg 進度信息*/void SetMessage(const char* pszMsg){m_strMessage = pszMsg;printf("%s\n", pszMsg);}/*** @brief 設置進度值* @param dPosition 進度值* @return 返回是否取消的狀態,true為不取消,false為取消*/bool SetPosition(double dPosition){m_dPosition = dPosition;TermProgress(m_dPosition);m_bIsContinue = true;return true;}/*** @brief 進度條前進一步* @return 返回是否取消的狀態,true為不取消,false為取消*/bool StepIt(){m_iCurStep ++;m_dPosition = m_iCurStep*1.0 / m_iStepCount;TermProgress(m_dPosition);m_bIsContinue = true;return true;}private:void TermProgress(double dfComplete){static int nLastTick = -1;int nThisTick = (int) (dfComplete * 40.0);nThisTick = MIN(40,MAX(0,nThisTick));// Have we started a new progress run? if( nThisTick < nLastTick && nLastTick >= 39 )nLastTick = -1;if( nThisTick <= nLastTick )return ;while( nThisTick > nLastTick ){nLastTick++;if( nLastTick % 4 == 0 )fprintf( stdout, "%d", (nLastTick / 4) * 10 );elsefprintf( stdout, "." );}if( nThisTick == 40 )fprintf( stdout, " - done.\n" );elsefflush( stdout );} };? ? 至此,一個控制臺的進度條就完成了,使用方式如下(注意:之前的博客中出現的LT_ConsoleProgress就是上面這個類):
void main() {CConsoleProcess *pProgress = new CConsoleProcess();//參考建立Erdas金字塔的那篇博客:http://blog.csdn.net/liminlu0314/article/details/6127755int f = CreatePyramids("C://Work//Data//ttttt.img", pProgress);if (f == RE_SUCCESS)printf("計算成功/n");elseprintf("計算失敗/n");delete pProgress; }
? ? 效果圖如下:
? ? 下面開始編寫一個基于QT界面的進度條類,首先是類定義,基于QT界面的,對于MFC界面的可以參考這個寫一個:
/** * @brief 進度條對話框類 * * 提供GUI程序的進度條類接口,來反映當前算法的進度值 */ class CProcessDlg : public QProgressDialog, public CProcessBase {Q_OBJECTpublic:/*** @brief 構造函數*/CProcessDlg(QWidget *parent = 0); /*** @brief 析構函數*/~CProcessDlg();/*** @brief 設置進度信息* @param pszMsg 進度信息*/void SetMessage(const char* pszMsg);/*** @brief 設置進度值* @param dPosition 進度值*/bool SetPosition(double dPosition);/*** @brief 進度條前進一步*/bool StepIt();public slots:void updateProgress(int); }; ? ? 接下來是實現部分代碼,具體和上面的控制臺類一樣,只不過是設置進度值都是設置在界面上的相應的控件中:/** * @brief 構造函數 */ CProcessDlg::CProcessDlg(QWidget *parent) :QProgressDialog(parent) {m_dPosition = 0.0;m_iStepCount = 100;m_iCurStep = 0;setModal(true);setLabelText(tr("處理中..."));setAutoClose(false);setAutoReset(false);setCancelButtonText(tr("取消"));setWindowTitle(tr("進度"));//禁用關閉按鈕setWindowFlags(Qt::WindowTitleHint | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); };/** * @brief 析構函數 */ CProcessDlg::~CProcessDlg() { };/** * @brief 設置進度信息 * @param pszMsg 進度信息 */ void CProcessDlg::SetMessage(const char* pszMsg) {if (pszMsg != NULL){m_strMessage = pszMsg;setLabelText(QString(pszMsg));} }/** * @brief 設置進度值 * @param dPosition 進度值 */ bool CProcessDlg::SetPosition(double dPosition) {m_dPosition = dPosition;setValue( std::min( 100u, ( uint )( m_dPosition*100.0 ) ) );QCoreApplication::instance()->processEvents(); if(this->wasCanceled())return false;return true; }/** * @brief 進度條前進一步,返回false表示終止操作 */ bool CProcessDlg::StepIt() {m_iCurStep ++;m_dPosition = m_iCurStep*1.0 / m_iStepCount;setValue( std::min( 100u, ( uint )( m_dPosition*100.0 ) ) );QCoreApplication::instance()->processEvents(); if(this->wasCanceled())return false;return true; }void CProcessDlg::updateProgress(int step) {this->setValue(step);QCoreApplication::instance()->processEvents(); } ? ? 至此,QT界面的進度條類已經完成,調用方式和上面控制臺的基本類似,示例代碼: //省略部分代碼CProcessDlg *pPro = new CProcessDlg();pPro->setWindowTitle(tr("正在執行柵格矢量化"));pPro->show();int iRev = ImagePolygonize(m_strInputName.c_str(), m_strOutputName.c_str(), pszFormat, pPro);delete pPro;? ? 這樣,我們基本上就實現了兩個進度條,一個控制臺,一個QT界面的。執行的效果圖如下:
? ? 那么在自己的算法中如何使用這個進度條類呢,下面給出一個簡單的算法,圖像反色算法:
/** * @brief 圖像反色 * @param pszSrcFile 輸入文件路徑 * @param pszDstFile 輸出文件路徑 * @param pszFormat 輸出文件格式,詳細參考GDAL支持數據類型 * @param pProcess 進度條指針 * @return 返回值,表示計算過程中出現的各種錯誤信息 */ int ImageAnticolor(const char* pszSrcFile, const char* pszDstFile, const char* pszFormat, CProcessBase* pProcess = NULL) {if(pProcess != NULL){pProcess->ReSetProcess();pProcess->SetMessage("執行圖像反色...");}if(pszSrcFile == NULL || pszDstFile == NULL)return RE_PARAMERROR;GDALAllRegister();GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszSrcFile, GA_ReadOnly );if( poSrcDS == NULL ){if(pProcess != NULL)pProcess->SetMessage("輸入文件不能打開,請檢查文件是否存在!");return RE_FILENOTEXIST;}GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);if( poDriver == NULL ){if(pProcess != NULL)pProcess->SetMessage("不能創建制定類型的文件,請檢查該文件類型GDAL是否支持創建!");GDALClose( (GDALDatasetH) poSrcDS );return RE_FILENOTSUPPORT;}//獲取圖像寬高和波段數int iXSize = poSrcDS->GetRasterXSize();int iYSize = poSrcDS->GetRasterYSize();int iBandCount = poSrcDS->GetRasterCount();//假設輸入圖像也是8U的數據GDALDataset *poDstDS = poDriver->Create(pszDstFile, iXSize, iYSize, iBandCount, GDT_Byte, NULL);double dGeoTrans[6] = {0};//設置仿射變換參數poSrcDS->GetGeoTransform(dGeoTrans);poDstDS->SetGeoTransform(dGeoTrans);//設置圖像投影信息poDstDS->SetProjection(poSrcDS->GetProjectionRef());DT_8U *pSrcData = new DT_8U[iXSize];DT_8U *pDstData = new DT_8U[iXSize];if(m_pProcess != NULL){m_pProcess->SetMessage("計算圖像反色...");m_pProcess->SetStepCount(iYSize*iBandCount); //設置進度條的總步長}//循環波段for(int iBand=1; iBand<=iBandCount; iBand++){GDALRasterBand *pSrcBand = poSrcDS->GetRasterBand(iBand);GDALRasterBand *pDstBand = poDstDS->GetRasterBand(iBand);for(int i=0; i<iYSize; i++) //循環圖像高{pSrcBand->RasterIO(GF_Read, 0, i, iXSize, 1, pSrcData, iXSize, 1, GDT_Byte, 0, 0);for(int j=0; j<iXSize; j++) //循環圖像寬pDstData[j] = 255 - pSrcData[j];pDstBand->RasterIO(GF_Write, 0, i, iXSize, 1, pDstData, iXSize, 1, GDT_Byte, 0, 0);if(m_pProcess != NULL){bool bIsCancel = m_pProcess->StepIt();if(!bIsCancel){RELEASE(pSrcData);RELEASE(pDstData);//關閉原始圖像和結果圖像GDALClose( (GDALDatasetH) poDstDS );GDALClose( (GDALDatasetH) poSrcDS );remove(pszDstFile); //刪除結果圖像if(pProcess != NULL)pProcess->SetMessage("圖像反色取消!");return RE_CANCEL;}}}}RELEASE(pSrcData);RELEASE(pDstData);//關閉原始圖像和結果圖像GDALClose( (GDALDatasetH) poDstDS );GDALClose( (GDALDatasetH) poSrcDS );if(pProcess != NULL)pProcess->SetMessage("圖像反色完成!");return RE_SUCCESS; }? ? 如果我要使用GDAL提供的算法,該怎么使用上面的進度條呢,很簡單,具體是要實現一個GDALProgressFunc()函數相同的一個使用__stdcall導出的函數即可,函數定義如下:/** * @brief 導出符號定義 */ #ifndef STD_API #define STD_API __stdcall #endif /** * \brief 調用GDAL進度條接口 * * 該函數用于將GDAL算法中的進度信息導出到CProcessBase基類中,供給界面顯示 * * @param dfComplete 完成進度值,其取值為 0.0 到 1.0 之間 * @param pszMessage 進度信息 * @param pProgressArg CProcessBase的指針 * * @return 返回TRUE表示繼續計算,否則為取消 */ int STD_API ALGTermProgress( double dfComplete, const char *pszMessage, void * pProgressArg ); ? ? 下面為該函數的實現代碼,請重點看第三個參數的使用方式:/** * \brief 調用GDAL進度條接口 * * 該函數用于將GDAL算法中的進度信息導出到CProcessBase基類中,供給界面顯示 * * @param dfComplete 完成進度值,其取值為 0.0 到 1.0 之間 * @param pszMessage 進度信息 * @param pProgressArg CProcessBase的指針 * * @return 返回TRUE表示繼續計算,否則為取消 */ int STD_API ALGTermProgress( double dfComplete, const char *pszMessage, void * pProgressArg ) {if(pProgressArg != NULL){CProcessBase * pProcess = (CProcessBase*) pProgressArg;pProcess->m_bIsContinue = pProcess->SetPosition(dfComplete);if(pProcess->m_bIsContinue)return TRUE;elsereturn FALSE;}elsereturn TRUE; }? ? 稍微對上面的函數體進行說明一下,關鍵是第三個參數,第三個參數其實就是我們上面定義的控制臺類獲取QT界面類的對象指針,只不過是專為一個void指針,在函數體中,我們需要將其轉為基類CProcessBase的指針,然后調用該基類的設置進度值函數即可。對于該函數的使用,下面還是以柵格矢量化為例來進行說明,廢話不多說,看代碼://前面省略很多代碼GDALRasterBandH hSrcBand = (GDALRasterBandH)poSrcDS->GetRasterBand(1);if(GDALPolygonize(hSrcBand, NULL, (OGRLayerH)poLayer, 0, NULL, ALGTermProgress, pProcess)!= CE_None){GDALClose( (GDALDatasetH) poSrcDS );if(pProcess != NULL){if(!pProcess->m_bIsContinue){pProcess->SetMessage("計算取消!");return RE_USERCANCEL;}else{pProcess->SetMessage("計算失敗!");return RE_PARAMERROR;}}return RE_PARAMERROR;}//后面省略部分代碼? ? 終于寫完了。好長啊~~~
轉載于:https://www.cnblogs.com/xiaowangba/archive/2012/02/20/6314032.html
總結
以上是生活随笔為你收集整理的GDAL算法进度条使用说明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux命令的学习
- 下一篇: westos讲解4