1. 程式人生 > >基於qml創建最簡單的圖像處理程序(2)-使用c++&qml進行圖像處理

基於qml創建最簡單的圖像處理程序(2)-使用c++&qml進行圖像處理

.cn turn isnull 按鈕 編寫 可能 finish height 通過

《基於qml創建最簡單的圖像處理程序》系列課程及配套代碼
基於qml創建最簡單的圖像處理程序(1)-基於qml創建界面
http://www.cnblogs.com/jsxyhelu/p/8343310.html
課程1附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%811.zip
基於qml創建最簡單的圖像處理程序(2)-使用c++&qml進行圖像處理
http://www.cnblogs.com/jsxyhelu/p/8361441.html
課程2附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%812.zip
基於qml創建最簡單的圖像處理程序(3)-使用opencv&qml進行圖像處理
http://www.cnblogs.com/jsxyhelu/p/8361443.html
課程3附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%813.zip
qml實現了不錯的界面,但是圖像處理這塊不是它強項,它能夠提供的就是qimage這樣的圖像,對像素的處理就是對圖像的處理,而最簡單、最直接的方法就是使用c++的代碼進行像素處理。 這裏就涉及到c++&qml聯合程序設計的具體內容了。這方面涉及到的東西有點多,首先我們需要解決的是qml和c++的聯合問題。當然我們在搭建這個框架的時候,可能會有比較多一些的問題—另一個方面,當框架搭建好了以後,使用起來會比較方便。 一、編寫按鈕觸發事件 現有的例子,已經實現了qml的界面,並且能夠打開、顯示一個新的圖像;我們甚至為後面的圖像處理預留了幾個按鈕的位置,下面我們首先就是要觸發這些按鈕的事件。
//灰度效果d
Button {
text: "灰度";
style: btnStyle;
onPressedChanged: {
busy.running = true;
// processor.process(fileDialog.fileUrl, ImageProcessor.Gray);
}
}
//浮雕效果
Button {
text: "浮雕";
style:
btnStyle;
onPressedChanged: {
busy.running = true;
// processor.process(fileDialog.fileUrl, ImageProcessor.Emboss);
}
}
//黑白效果
Button {
text: "黑白";
style: btnStyle;
onPressedChanged: {
busy.running = true;
// processor.process(fileDialog.fileUrl, ImageProcessor.Binarize);
}
} 這個地方有一個小細節,那就是 onPressedChanged() onClick() 的區別。這兩者表示的都是“按下”這個事件,他們的不同在於onClick()要多了一個“按下後擡起”的動作。所以一般來說,對於桌面運用,click用的多一點,而對於Android,onPressedChanged多一點。 二、觸發圖像處理算法 我們可以看到上面代碼中,每一種處理後面,都有一行註釋,調用的是processor對象的一個函數,那麽這個函數是從哪裏來的了?它的定義來自這裏 //需要特別註意,這個組件來自imageprocessor這個類,通過這種方法進行集成
ImageProcessor {
id: processor;
onFinished: {
imageViewer.source = "file:///" +newFile;
}
} 它的意思是processor對象是ImageProcessor類的一個實例,那麽ImageProcessor又是從哪裏來的了? 它的定義來自於 技術分享圖片 //將c++中定義的類給接過來,在這個定義中,ImageProcessor是c++中函數名,GO.ImageProcessor是你在qml中使用的名稱
qmlRegisterType<ImageProcessor>("GO.ImageProcessor", 1, 0,"ImageProcessor"); 其中qmlRegisterType是類的引入,類似dllimport之類,而 <ImageProcessor> "ImageProcessor" 一般來說,都是來自於你的c++的函數名稱;而 "GO.ImageProcessor" 是你在qml中的頭文件. 此外,1,0是你的版本號。 所以這個地方有兩個頭文件,在main.cpp中,引入 #include "imageProcessor.h" 而在qml中,這樣引入 import GO.ImageProcessor 1.0 那麽我們在這裏主要討論的就是如何從c++中將行數引接過來的。 、C++中具體算法實現 那我們就來看c++類中的ImageProcessor 是如何實現的,它的代碼地址來自: 技術分享圖片 它的原型為: void process(QString sourceFile, ImageProcessor::ImageAlgorithm algorithm)
{
QFileInfo fi(sourceFile);
QString destFile = QString("%1/%2_%3").arg(m_tempPath).arg((int)algorithm).arg(fi.fileName());
AlgorithmRunnable *r = new AlgorithmRunnable(sourceFile,destFile,algorithm,this);
m_runnables.append(r);
r->setAutoDelete(false);
QThreadPool::globalInstance()->start(r);
} 它設定了一系列參數,主要是創建了AlgorithmRunnalbe,然後通過QThreadPool打開新線程運行算法。那麽主要的函數體在AlgorithmRunnable中的。由於涉及到較多的具體內容,這裏不展開說明,大家可以參考全部代碼。 我們關註的是圖像處理函數,在這個項目中實現了以下內容: //具體的圖像處理算法,註意圖片處理的結果直接保存到了destFile中去//
static void _gray(QString sourceFile, QString destFile)
{
QImage image(sourceFile);
if(image.isNull())
{
qDebug() << "load " << sourceFile << " failed! ";
return;
}
qDebug() << "depth - " << image.depth();

int width = image.width();
int height = image.height();
QRgb color;
int gray;
for(int i = 0; i < width; i++)
{
for(int j= 0; j < height; j++)
{
color = image.pixel(i, j);
gray = qGray(color);
image.setPixel(i, j, qRgba(gray, gray, gray, qAlpha(color)));
}
}

image.save(destFile);
}

static void _binarize(QString sourceFile, QString destFile)
{
QImage image(sourceFile);
if(image.isNull())
{
qDebug() << "load " << sourceFile << " failed! ";
return;
}
int width = image.width();
int height = image.height();
QRgb color;
QRgb avg;
QRgb black = qRgb(0, 0, 0);
QRgb white = qRgb(255, 255, 255);
for(int i = 0; i < width; i++)
{
for(int j= 0; j < height; j++)
{
color = image.pixel(i, j);
avg = (qRed(color) + qGreen(color) + qBlue(color))/3;
image.setPixel(i, j, avg >= 128 ? white : black);
}
}
image.save(destFile);
}

static void _emboss(QString sourceFile, QString destFile)
{
QImage image(sourceFile);
if(image.isNull())
{
qDebug() << "load " << sourceFile << " failed! ";
return;
}
int width = image.width();
int height = image.height();
QRgb color;
QRgb preColor = 0;
QRgb newColor;
int gray, r, g, b, a;
for(int i = 0; i < width; i++)
{
for(int j= 0; j < height; j++)
{
color = image.pixel(i, j);
r = qRed(color) - qRed(preColor) + 128;
g = qGreen(color) - qGreen(preColor) + 128;
b = qBlue(color) - qBlue(preColor) + 128;
a = qAlpha(color);
gray = qGray(r, g, b);
newColor = qRgba(gray, gray, gray, a);
image.setPixel(i, j, newColor);
preColor = newColor;
}
}
image.save(destFile);
}
//END 具體的圖像處理算法,註意圖片處理的結果直接保存到了destFile中去// 甚至不用去看算法的實現(因為最後我們肯定是要使用OpenCV來做圖像處理的),這3個圖像處理的函數都是非常統一的 static void _binarize(QString sourceFile, QString destFile) 比如返回類型為void,第一個參數為輸入圖像,第二個參數為輸出圖片。從這裏也可以看出,在我們這個項目中,是通過地址(而不是內存)來傳遞數據的。如果我們想要添加新的算法,修改現有算法,直接修改這幾個函數、添加相關界面就可以。 技術分享圖片 而下一步,最關鍵的一步,也是原書例子沒有實現的,就是添加OpenCV的代碼,使用它來替代進行圖像處理。



來自為知筆記(Wiz)



附件列表

基於qml創建最簡單的圖像處理程序(2)-使用c++&qml進行圖像處理