2014-06-15 70 views
7

的特定區域我想只計算該圖像的小插曲區域,像我有圖像here如何提取圖像

我怎麼可以算或迭代/只在應用暗角區域通過,離開其他地區?我只想在應用暈影的區域應用該算法,我嘗試了這種方法,就像給紅色的標量並提取發現紅色的區域,但它不工作就像沒有給出結果,因爲當朝向中心時顏色變得更亮的形象。

vignette由圖像強度隨以下掩碼相乘變暗角落和邊緣: enter image description here

這是原始圖像here

blending overlay**only vignette part of** vignette imageoriginal image

這裏是我的代碼混合覆蓋

void blending_overlay(Mat& img1 , Mat& img2 , Mat& out) 
{ 
Mat result(img1.size(), CV_32FC3); 
for(int i = 0; i < img1.size().height; ++i){ 
    for(int j = 0; j < img1.size().width; ++j){ 

     for (int c=0 ; c<img1.channels();c++){ 
      float target = (float)img1.at<uchar>(i, 3*j+c)/255. ; 
      float blend = (float)img2.at<uchar>(i, 3*j+c)/255. ; 

      if(target > 0.5){ 
       result.at<float>(i, 3*j+c) = ((1 - (1-2*(target-0.5)) * (1-blend))); 

       } 
      else{ 
       result.at<float>(i, 3*j+c) = ((2*target) * blend); 
       } 
     } 
    } 
} 
result.convertTo(out,CV_8UC3,255); 
} 

int main(int argc, char** argv) 
{ 
    Mat Img1=imread("D:\\Vig.png",-1); // the vignete in the question 
    Mat Img2=imread("D:\\i.png"); // the iamge in the question 
    cv::resize(Img1,Img1,Img2.size()); 
    Img1.convertTo(Img1,CV_32FC4,1.0/255.0); 
    Img2.convertTo(Img2,CV_32FC3,1.0/255.0); 

    vector<Mat> ch; 
    split(Img1,ch); 

    Mat mask = ch[3].clone();    // here's the vignette 

    ch.resize(3); 

    Mat I1,I2,result; 

    cv::multiply(mask,ch[0],ch[0]); 
    cv::multiply(mask,ch[1],ch[1]); 
    cv::multiply(mask,ch[2],ch[2]); 
    merge(ch,I1); 
    vector<Mat> ch2(3); 
    split(Img2, ch2); 
    cv::multiply(1.0-mask,ch2[0],ch2[0]); 
    cv::multiply(1.0-mask,ch2[1],ch2[1]); 
    cv::multiply(1.0-mask,ch2[2],ch2[2]); 
    merge(ch2,I2); 
    I1.convertTo(I1,CV_8UC3,255); 
    I2.convertTo(I2,CV_8UC3,255); 
    result=I1+I2; // The image with the vignette in the question 
    result.convertTo(result,CV_8UC4,255); 
    Mat result2; 
    Mat mask2; 
    Mat image = imread ("D:\\i.png"); // image in the question 
    blending_overlay(image,result,result2,mask2); 
    imshow("Image",result2); 
    waitKey(0); 
} 

它適用於與原始圖像混合小品形象,但我只想與原來的圖像混合的暗角部分來自小插曲圖像

Required Result

我得到的結果是this

+0

你能簡單地提取想要的圖像部分,過程,然後將這些像素複製回原來的形象呢?另外,請原諒我的無知,但什麼是小插曲**? – rayryeng

+0

這是小插曲http://www.lifeclever.com/wp-content/uploads/2007/01/vignette_edge_no_image.jpg – AHF

+0

我想應用小插曲後的圖像部分 – AHF

回答

8

你有一些錯誤。 首先你似乎在使用顏色混合來選擇屏幕和混合混合,但你應該使用強度。我認爲photoshop可能會在hsv色彩空間中進行混合,但在這種情況下,rgb似乎可以像使用L =(r + g + b)/ 3作爲強度那樣工作。

此外,你的代碼是混合圖像和小插曲和圖像的alpha混合(沒有你問題中的代碼匹配在你的問題中生成的圖像?)。相反,您需要一個與您想要應用小插圖的區域中的小插圖等同的「遮罩」,並且在您不希望應用它的區域中等於0.5。

所以我把你提供的圖案(最左邊)有一個alpha通道(左邊第二個), 做一個alpha混合灰色(右邊第二個)以獲得一個圖像用作頂部圖像混合疊加(最右邊)。在頂部圖像是灰色的情況下,當與其他圖像混合時,底部將顯示但不變。這是因爲在這兩行代碼中:

_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend))); 
_result[j][c] = 2 * target * blend; 

如果blend = 0.5,則結果爲設置爲目標。

 Vignette    Alpha     Gray    Blend Image (top) 

enter image description here

我已經包含所生成的圖像,以及將碼做以下。所需的圖像顯示在左側,生成的圖像顯示在右側。據我所知,他們是一樣的。 通過在中間不轉換爲CV_UC3,但在blend_overlay()中傳遞FC3參數,可以獲得準確度的提高。

   Required         Generated 

enter image description here

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <iostream>  // std::cout 
#include <vector>  // std::vector 
using namespace std; 
using namespace cv; 

void blending_overlay2(Mat& bot, Mat& top, Mat& out) 
{ 
    Mat result(bot.size(), CV_32FC3); 

    // Extract the calculate I = (r + g + b)/3 
    Mat botf; 
    bot.convertTo(botf, CV_32FC3, 1.0/255.0); 
    std::vector<cv::Mat> planes(3); 
    cv::split(botf, planes); 

    cv::Mat intensity_f((planes[0] + planes[1] + planes[2])/3.0f); 
    cv::Mat L; 
    intensity_f.convertTo(L, CV_8UC1, 255.0); 
    //cv::imshow("L", L); 


    for(int i = 0; i < bot.size().height; ++i) 
    { 
     // get pointers to each row 
     cv::Vec3b* _bot = bot.ptr<cv::Vec3b>(i); 
     cv::Vec3b* _top = top.ptr<cv::Vec3b>(i); 
     cv::Vec3f* _result = result.ptr<cv::Vec3f>(i); 
     uchar* _L = L.ptr<uchar>(i); 

     // now scan the row 
     for(int j = 0; j < bot.size().width; ++j) 
     { 
      for (int c=0; c < bot.channels(); c++) 
      { 
       float target = float(_bot[j][c])/255.0f; 
       float blend = float(_top[j][c])/255.0f; 

       if(_L [j] > 128) 
       { 
        _result[j][c] = 2 * (blend + target - target * blend) - 1; 
        // Why isn't the below line simplified like above? 
        //_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend))); 
       } 
       else 
       { 
        _result[j][c] = 2 * target * blend; 
       } 
      } 
     } 
    } 
    result.convertTo(out, CV_8UC3, 255); 
} 

int main(int argc, char** argv) 
{ 
    Mat Img1=cv::imread("kqw0D.png",-1); // the vignete in the question 

    Mat Img2=cv::imread("i.png"); // the iamge in the question 
    Mat image = Img2.clone(); 
    cv::resize(Img1,Img1,Img2.size()); 
    Img1.convertTo(Img1,CV_32FC4,1.0/255.0); 
    Img2.convertTo(Img2,CV_32FC3,1.0/255.0); 

    // split off the alpha channel from the vignette 
    vector<Mat> ch; 
    split(Img1,ch); 
    Mat alpha = ch[3].clone();    // here's the vignette 
    Mat alpha_u; 
    alpha.convertTo(alpha_u,CV_8UC1,255); 
    imshow("alpha",alpha); 

    // drop the alpha channel from vignette 
    ch.resize(3); 

    // pre-mutiply each color channel by the alpha 
    // and merge premultiplied color channels into 3 channel vignette I1 
    Mat I1; 
    cv::multiply(alpha, ch[0], ch[0]); 
    cv::multiply(alpha, ch[1], ch[1]); 
    cv::multiply(alpha, ch[2], ch[2]); 
    merge(ch, I1); 

    // Now make the vignette = 0.5 in areas where it should not be "applied" 
    Mat I2; 
    vector<Mat> ch2; 
    cv::Mat half = cv::Mat::ones(Img2.rows, Img2.cols, CV_32FC1) * 0.5; 
    cv::multiply(1.0f - alpha, half, half); 
    ch2.push_back(half); 
    ch2.push_back(half); 
    ch2.push_back(half); 
    //split(Img2, ch2); 
    //cv::multiply(1.0f - alpha, ch2[0], ch2[0]); 
    //cv::multiply(1.0f - alpha, ch2[1], ch2[1]); 
    //cv::multiply(1.0f - alpha, ch2[2], ch2[2]); 
    merge(ch2, I2); 

    // result = alpha * vignette + (1 - alpha) * gray; 
    Mat top; 
    top=I1+I2; 


    // make I1 8 bit images again 
    I1.convertTo(I1,CV_8UC3,255); 
    I2.convertTo(I2,CV_8UC3,255); 
    top.convertTo(top,CV_8UC3,255); 
    //imshow("I1",I1); 
    //imshow("I2",I2); 
    //imshow("top",top); 

    Mat result2; 
    blending_overlay2(image,top, result2); 
    imshow("Voila!", result2); 
    imwrite("voila.png", result2); 
    waitKey(0); 
} 
+0

+1以清除它! – rayryeng

+0

其實圖像已經包含小插曲,就像我讀到的圖像是在我的問題上面的圖像,所以我如何分別閱讀他們,就像你寫'地毯圖像'和'墊子小插曲' – AHF

+0

@AHF現在我真的不明白你正在努力實現。如果您只能訪問應用了小插圖的圖像,但不能訪問小插圖或原始圖像,則獲取解決方案需要進行一些假設。你需要在你的問題中拼出你真正想要做的事情。即給你提供的圖像,你想要什麼輸出? – Bull