日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qimage像素级操作

發(fā)布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qimage像素级操作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這篇文章主要闡述了如何使用Qt在像素級別上對圖像進行操作,并實現(xiàn)了一些圖像效果,這些效果主要有:灰度,模糊,銳化,添加相框,金屬質(zhì)感,改變圖像飽和度,亮度還有白平衡。

scanLine 返回某一行數(shù)據(jù),轉換為QRgb指針可進行直接有效的像素存取操作。

介紹

文章中,我們將討論在Qt中修改圖像的一些技術和算法,在這之前,你必須知道在Qt中操作圖像的一些方法。

.在Qt中有兩種表示圖像的類,Qt:QImage和QPixmap,還有QBitmap來存儲單色的圖像,比如遮罩,QPicture在存儲QPainter的一些操作指令。

? 當我們想要在屏幕上繪制圖像的時候,最快的方法就是使用QPixmap,不過壞處就是無法訪問和修改像素;

QImage在IO操作中有很快的速度,并且給出了訪問像素的接口,這篇文章中我們就使用這個類。

.如果你是要處理大的圖片,比如攝像頭拍攝的照片,這種情況最好是將原圖縮小之后作為預覽圖顯示在屏幕上,除非我們允許用戶縮放圖像。有兩種加載并縮放圖像的方法。

。將圖像加載進QImage或者QPixmap,然后調(diào)整大小:

?

[cpp]?view plain?copy

  • QImage?image("sample.png");??
  • image?=?image.scaled(width,?height);??

  • 使用QImageReader來讀取和縮放圖片,然后再加載進QImage中。QImageReader無法將一張圖片加載進QPixmap中去,但是可以使用靜態(tài)方法 QPixmap::fromImage(QImage img)從QImage中加載進QPixmap。這個方法非???#xff0c;并且不需要加載大圖的內(nèi)存開銷:

    ?

    ?

    [cpp]?view plain?copy

  • QImageReader?imgReader("sample.png");??
  • imgReader.setScaledSize(QSize(width,?height));??
  • QImage?*?image;??
  • imgReader.read(image);??

  • 。每一張圖片都是由像素點組成,每一個像素都有三個通道:紅,綠,藍,還有一個alpha通道來保存透明度(JPEG格式的圖片不支持透明)。每個通道的值是0-255,三個通道都是0的話,表示黑色,都是255表示白色。這篇文章中我們用RGB來表示一種顏色,也就是三個通道的值。

    ?

    ?

    。相比于一個像素一個像素地讀取,uchar * ?QImage::scanLine(int i)可以一次讀取整行的像素值,會更加高效,下面的例子就是按行讀取的例子,也是我們將要講的第一個例子,轉灰度圖。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::greyScale(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(origin->width(),?origin->height(),?QImage::Format_ARGB32);??
  • ???
  • ????QRgb?*?line;??
  • ???
  • ????for(int?y?=?0;?y<newImage->height();?y++){??
  • ????????QRgb?*?line?=?(QRgb?*)origin->scanLine(y);??
  • ???
  • ????????for(int?x?=?0;?x<newImage->width();?x++){??
  • ????????????int?average?=?(qRed(line[x])?+?qGreen(line[x])?+?qRed(line[x]))/3;??
  • ????????????newImage->setPixel(x,y,?qRgb(average,?average,?average));??
  • ????????}??
  • ???
  • ????}??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    灰度

    我們要學習的第一個技術就是將彩色圖轉換成灰度圖,我們首先要明白的一點就是,其實標準的灰度圖就是每個像素點的三個通道的值一樣或者近似,我們的策略就是將每個像素的每個通道的值都調(diào)成一樣,取R,G,B值為三者的算數(shù)平均數(shù)就可以了,比如原色是RGB(169,204,69), 那么最終的RGB就是(169+204+69)/3 = 147.

    ?

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::greyScale(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(origin->width(),?origin->height(),?QImage::Format_ARGB32);??
  • ???
  • ????QColor?oldColor;??
  • ???
  • ????for(int?x?=?0;?x<newImage->width();?x++){??
  • ????????for(int?y?=?0;?y<newImage->height();?y++){??
  • ????????????oldColor?=?QColor(origin->pixel(x,y));??
  • ????????????int?average?=?(oldColor.red()+oldColor.green()+oldColor.blue())/3;??
  • ????????????newImage->setPixel(x,y,qRgb(average,average,average));??
  • ????????}??
  • ????}??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    原始圖

    ?

    灰度圖

    ?

    亮度調(diào)節(jié)

    就如之前我們提到的,白色用RGB(255,255,255)表示,黑色用RGB(0,0,0)表示,所以如果我們需要提高圖片的亮度(顏色接近白色),我們需要同時增加三個通道的數(shù)值,反之就是變暗。

    ?

    在這里我們添加了一個函數(shù)參數(shù)來決定要提高多少亮度,如果參數(shù)是負數(shù)的話就是減少亮度了。在每個通道都加上delta值之后,需要做的就是讓它不要低于0且不要高于255.

    原圖

    加亮圖 Delta = 30

    ?

    ?

    暖色調(diào)

    當我們說一一幅暖色調(diào)的圖片的時候通常是因為這張圖色調(diào)偏黃。我們沒有黃色的通道,但是紅色和綠色混合起來就是黃色,所以我們增加這兩個通道值,然后藍色通道值不變就好了。

    ?

    我們使用一個delta參數(shù)來決定增加紅色和綠色通道的值。一張暖色的圖片能夠給人一種復古效果,如果是有沙子的圖片,圖片將會更加生動。

    ?

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::warm(int?delta,?QImage?*?origin){??
  • ????QImage?*newImage?=?new?QImage(origin->width(),?origin->height(),?QImage::Format_ARGB32);??
  • ???
  • ????QColor?oldColor;??
  • ????int?r,g,b;??
  • ???
  • ????for(int?x=0;?x<newImage->width();?x++){??
  • ????????for(int?y=0;?y<newImage->height();?y++){??
  • ????????????oldColor?=?QColor(origin->pixel(x,y));??
  • ???
  • ????????????r?=?oldColor.red()?+?delta;??
  • ????????????g?=?oldColor.green()?+?delta;??
  • ????????????b?=?oldColor.blue();??
  • ???
  • ????????????//we?check?if?the?new?values?are?between?0?and?255??
  • ????????????r?=?qBound(0,?r,?255);??
  • ????????????g?=?qBound(0,?g,?255);??
  • ???
  • ????????????newImage->setPixel(x,y,?qRgb(r,g,b));??
  • ????????}??
  • ????}??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    暖色圖 Delta = 30

    ?

    冷色調(diào)

    如果說暖色調(diào)的圖片偏黃色,那么冷色調(diào)的圖片應該就是偏藍色了。在這個方法里面我們只增加藍色通道的值,紅色和綠色的值不變。

    冷色調(diào)的圖片可以聯(lián)想到未來,死亡或者,冷。

    ?

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::cool(int?delta,?QImage?*?origin){??
  • ????QImage?*newImage?=?new?QImage(origin->width(),?origin->height(),?QImage::Format_ARGB32);??
  • ???
  • ????QColor?oldColor;??
  • ????int?r,g,b;??
  • ???
  • ????for(int?x=0;?x<newImage->width();?x++){??
  • ????????for(int?y=0;?y<newImage->height();?y++){??
  • ????????????oldColor?=?QColor(origin->pixel(x,y));??
  • ???
  • ????????????r?=?oldColor.red();??
  • ????????????g?=?oldColor.green();??
  • ????????????b?=?oldColor.blue()+delta;??
  • ???
  • ????????????//we?check?if?the?new?value?is?between?0?and?255??
  • ????????????b?=?qBound(0,?b,?255);??
  • ???
  • ????????????newImage->setPixel(x,y,?qRgb(r,g,b));??
  • ????????}??
  • ????}??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    冷色調(diào)圖 Delta = 30

    ?

    飽和度

    我們已經(jīng)說了,顏色由三個通道組成:紅,綠,藍,盡管如此,RGB不是唯一一個表示色彩的方式,在這里,我們使用HSL格式表示色彩 -?hue(色相), saturation(飽和度), lightness(明度)。

    飽和的圖像擁有更加生動的顏色,通常會比較好看,但是有一點要記住:不要濫用飽和度,因為很容易出現(xiàn)失真。

    ?

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::saturation(int?delta,?QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(origin->width(),?origin->height(),?QImage::Format_ARGB32);??
  • ???
  • ????QColor?oldColor;??
  • ????QColor?newColor;??
  • ????int?h,s,l;??
  • ???
  • ????for(int?x=0;?x<newImage->width();?x++){??
  • ????????for(int?y=0;?y<newImage->height();?y++){??
  • ????????????oldColor?=?QColor(origin->pixel(x,y));??
  • ???
  • ????????????newColor?=?oldColor.toHsl();??
  • ????????????h?=?newColor.hue();??
  • ????????????s?=?newColor.saturation()+delta;??
  • ????????????l?=?newColor.lightness();??
  • ???
  • ????????????//we?check?if?the?new?value?is?between?0?and?255??
  • ????????????s?=?qBound(0,?s,?255);??
  • ???
  • ????????????newColor.setHsl(h,?s,?l);??
  • ???
  • ????????????newImage->setPixel(x,?y,?qRgb(newColor.red(),?newColor.green(),?newColor.blue()));??
  • ????????}??
  • ????}??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    ?

    原圖

    ?

    ?

    飽和的圖片 Delta=30

    ?

    模糊

    這個效果相對于之前的有一點點復雜。我們會用到一個卷積濾波器,根據(jù)當前像素的顏色和相鄰像素的顏色來獲得一個新的顏色。同時還有一個kernel的矩陣來決定計算中相鄰像素的影響程度。

    ?

    原像素會在矩陣的中心,因此我們會使用基數(shù)行的行和列。我們不會修改邊緣的像素點,因為那些點沒有我們需要的相鄰像素點,雖然我們也可以只使用有效的像素點。

    ?

    舉了例子,讓我們來看看如何計算像素的RGB值。下面的三個舉證代表著當前像素和鄰接像素的RGB值,最中間的是當前像素。

    R = 20 102 99
    150 200 77?
    170 210 105

    G = 22 33 40
    17 21 33
    8 15 24

    B = 88 70 55
    90 72 59
    85 69 50

    ?

    Kenel =? 0 2 0
    2?5 2
    0 2 0

    ?

    使用濾波器進行計算:

    r = ( (102*2) + (150*2) + (200*5) + (77*2) + (210*2) ) / (2+2+5+2+2) = 159
    g = ( (33*2) + ( 17*2) + (21*5) + (33*2) + (15*2) ) / (2+2+5+2+2) = 23
    b = ( (70*2) + (90*2) + (72*5) + (59*2) + (69*2) ) / (2+2+5+2+2) = 72

    ?

    由原始的RGB(200, 21, 72)得到了RGB(159, 23, 72). ?發(fā)現(xiàn)最大的變化是紅色的通道,因為紅色通道的值差距最大。

    ?

    在修改肖像照片的時候通常會使用到模糊的技術,它能后掩蓋住皮膚的瑕疵。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::blur(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(*origin);??
  • ???
  • ????int?kernel?[5][5]=?{{0,0,1,0,0},??
  • ????????????????????????{0,1,3,1,0},??
  • ????????????????????????{1,3,7,3,1},??
  • ????????????????????????{0,1,3,1,0},??
  • ????????????????????????{0,0,1,0,0}};??
  • ????int?kernelSize?=?5;??
  • ????int?sumKernel?=?27;??
  • ????int?r,g,b;??
  • ????QColor?color;??
  • ???
  • ????for(int?x=kernelSize/2;?x<newImage->width()-(kernelSize/2);?x++){??
  • ????????for(int?y=kernelSize/2;?y<newImage->height()-(kernelSize/2);?y++){??
  • ???
  • ????????????r?=?0;??
  • ????????????g?=?0;??
  • ????????????b?=?0;??
  • ???
  • ????????????for(int?i?=?-kernelSize/2;?i<=?kernelSize/2;?i++){??
  • ????????????????for(int?j?=?-kernelSize/2;?j<=?kernelSize/2;?j++){??
  • ????????????????????color?=?QColor(origin->pixel(x+i,?y+j));??
  • ????????????????????r?+=?color.red()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????????g?+=?color.green()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????????b?+=?color.blue()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????}??
  • ????????????}??
  • ???
  • ????????????r?=?qBound(0,?r/sumKernel,?255);??
  • ????????????g?=?qBound(0,?g/sumKernel,?255);??
  • ????????????b?=?qBound(0,?b/sumKernel,?255);??
  • ???
  • ????????????newImage->setPixel(x,y,?qRgb(r,g,b));??
  • ???
  • ????????}??
  • ????}??
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    ?

    模糊圖

    ?

    銳化

    像模糊中一樣,銳化一張圖片也會使用一個卷積濾波器,但是kernel矩陣是不一樣的,相鄰像素對應的值是負的。

    銳化能夠處理模糊的照片,能夠提升細節(jié)。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::sharpen(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(*?origin);??
  • ???
  • ????int?kernel?[3][3]=?{{0,-1,0},??
  • ????????????????????????{-1,5,-1},??
  • ????????????????????????{0,-1,0}};??
  • ????int?kernelSize?=?3;??
  • ????int?sumKernel?=?1;??
  • ????int?r,g,b;??
  • ????QColor?color;??
  • ???
  • ????for(int?x=kernelSize/2;?x<newImage->width()-(kernelSize/2);?x++){??
  • ????????for(int?y=kernelSize/2;?y<newImage->height()-(kernelSize/2);?y++){??
  • ???
  • ????????????r?=?0;??
  • ????????????g?=?0;??
  • ????????????b?=?0;??
  • ???
  • ????????????for(int?i?=?-kernelSize/2;?i<=?kernelSize/2;?i++){??
  • ????????????????for(int?j?=?-kernelSize/2;?j<=?kernelSize/2;?j++){??
  • ????????????????????color?=?QColor(origin->pixel(x+i,?y+j));??
  • ????????????????????r?+=?color.red()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????????g?+=?color.green()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????????b?+=?color.blue()*kernel[kernelSize/2+i][kernelSize/2+j];??
  • ????????????????}??
  • ????????????}??
  • ???
  • ????????????r?=?qBound(0,?r/sumKernel,?255);??
  • ????????????g?=?qBound(0,?g/sumKernel,?255);??
  • ????????????b?=?qBound(0,?b/sumKernel,?255);??
  • ???
  • ????????????newImage->setPixel(x,y,?qRgb(r,g,b));??
  • ???
  • ????????}??
  • ????}??
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    銳化圖

    ?

    添加相框

    繪制一個相框是非常見到那的,我們只需要把相框在原圖上面繪制就可以了。這里假設我們已經(jīng)有一個和圖片一樣大小的相框了,不一樣的話要resize到一樣大。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::drawFrame(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(*?origin);??
  • ????QPainter?painter;??
  • ???
  • ????painter.begin(newImage);??
  • ???
  • ????painter.drawImage(0,0,?QImage(":images/frame.png"));??
  • ???
  • ????painter.end();??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    相框

    添加相框之后

    ?

    金屬效果

    這個例子中我們會結合幾種技術來獲得一種效果。下面是處理的步驟:

    1.調(diào)整圖像的亮度,獲得一個較暗的圖片。

    2.將圖像轉成灰度。

    3.將灰度圖繪制在金屬的紋理上,透明度50%。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::metal(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(":images/metal.png");??
  • ????QImage?*?darkImage?=?brightness(-100,?origin);??
  • ????QImage?*?greyImage?=?greyScale(darkImage);??
  • ????QPainter?painter;??
  • ???
  • ????painter.begin(newImage);??
  • ???
  • ????painter.setOpacity(0.5);??
  • ????painter.drawImage(0,?0,?*?greyImage);??
  • ???
  • ????painter.end();??
  • ???
  • ????delete?greyImage;??
  • ????delete?darkImage;??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    ?

    ?

    原圖

    ?

    金屬紋理

    ?

    最終效果

    ?

    模糊的邊框

    最后再來學習一個融合的效果,這次我們想要做的是模糊圖片外延的部分,讓視線的焦點聚集在圖片的中間。

    ?

    我們將會使用一張遮罩圖片,來決定需要模糊的部分,具體的操作步驟如下:

    1.從原圖獲取一張完全模糊的圖片。

    2.使用QPainter的一種融合模式,通過遮罩圖片截取出一個模糊的相框。點這里可以學習到更多的QPainter的融合模式。

    3.在原圖上繪制出模糊的邊框。

    ?

    [cpp]?view plain?copy

  • QImage?*?MainWindow::blurFrame(QImage?*?origin){??
  • ????QImage?*?newImage?=?new?QImage(*?origin);??
  • ????QImage?*?blurredImage?=?blur(newImage);??
  • ????QImage?*?mask?=?new?QImage(":images/mask.png");??
  • ????QPainter?painter;??
  • ???
  • ????//Using?the?composition?mode?SourceAtop?we?get?a?blurred?frame?stored?in?QImage?mask??
  • ????painter.begin(mask);??
  • ???
  • ????painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);??
  • ????painter.drawImage(0,?0,?*?blurredImage);??
  • ???
  • ????painter.end();??
  • ???
  • ????//With?our?new?frame?we?simply?draw?it?over?the?original?image??
  • ????painter.begin(newImage);??
  • ???
  • ????painter.setCompositionMode(QPainter::CompositionMode_SourceOver);??
  • ????painter.drawImage(0,?0,?*?mask);??
  • ???
  • ????painter.end();??
  • ???
  • ????delete?mask;??
  • ????delete?blurredImage;??
  • ???
  • ????return?newImage;??
  • }??
  • ?

    ?

    原圖

    ?

    遮罩

    ?

    模糊的邊框

    ?

    最終效果

    ?

    手機Demo

    你可以下載這個手機Demo的源碼,里面包含了文章中的源碼,在這個應用中,包含了3張462*260的圖片。測試應用的時候,你只要選擇其中一張并應用下面的效果就可以了。

    ?

    總結

    這篇文章應該可以成為你圖像處理的入門,但是一切皆有可能。你可以修改這些方法,整合這些方法,使用其他的技術等等。想象力才是你唯一的限制。

    總結

    以上是生活随笔為你收集整理的Qimage像素级操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。