2017-08-10 29 views
4

透明な平面を持つPNG画像をロードしています。グレースケールに変換すると、画像の透明領域が黒く表示され、デフォルトの背景になります。私はそれらを白くする必要があります。私に何ができる ?透明なPNGの背景色を設定する

[これは、透明性を維持する方法についての一般的な問題ではありません。]

+1

トランスペアレンプレーンは統一されていますか? (つまり、アルファコンポーネントのいくつの値を取ることができますか?2つ)最初のアイデア:[白い背景イメージでイメージを描く](https://stackoverflow.com/questions/20957433/how-to-draw-a-transparent-イメージオーバーライブカメラフィードインオープンカルチ#20958245)を使用してグレースケールに変換します。 2番目のアイデア:最初にグレースケールに変換してから、各ピクセルを繰り返して、元のイメージにあるすべてのピクセルを新しいピクセルで白に変換します(アルファコンポーネント)(https://stackoverflow.com/questions/18491998/creating-transparent-image -in-opencv)を指定したしきい値以下にします。 –

+0

@GabrielDevillers:実際には分かりません。私はPNGを読み込み、黒のピクセルでグレースケール画像を取得しています。私はアルファ平面は見ません。 –

+0

@ YvesDaoust画像をどのように読み込みますか?私はあなたの説明に基づいて、グレースケールと推測します。あなたは 'IMREAD_UNCHANGED'でそれをロードする必要があります。そうすれば、完全な4チャンネルの画像を取得し、その後処理をすることができます。 –

答えて

0

あなたがIMREAD_UNCHANGEDを渡さずimreadとPNGを読めば、あなたは3チャンネルBGRイメージを持っています。 4番目のアルファチャンネル(0 =完全に透明、255 =完全に表示されている)がある場合、として文書put itとして切り取られます。

ピクセルのBGR部分が黒色になっているため、透明ピクセルがある場所は黒いピクセルになります。 (Vec3b(0, 0, 0))。以下

あなたが納得していない場合は、(IMREAD_UNCHANGEDパラメータwihout imread)BGRとしてを開こうとすると、ディスプレイ(imshowその後、waitkey両方の画像:

original logo from wikipediaenter image description here

彼らはこのページで似てますがまたはGimpで、最初のものは黒い背景を持つべきですが、2番目のものは赤い背景を持つべきです。

最初の解決策:Michael Jep息子のoverlayImage function

#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgcodecs.hpp> 
int main(int argc, char** argv) { 
    cv::Mat img_4_channels; 
    img_4_channels = cv::imread(argv[1], cv::IMREAD_UNCHANGED); // gives 8UC4 
    // img_4_channels = cv::imread(argv[1]); // inappropriate: gives 8UC3 

    cv::Mat background = cv::Mat(img_4_channels.size(), CV_8UC3, cv::Vec3b(255, 255, 255)); // white background 
    overlayImage(background, img_4_channels, img_3_channels, cv::Point2i(0, 0)); 

    cv::imshow("3 channels", img_3_channels); 
} 

第二の溶液:ローザGronchi

によってthis answerこの溶液(いや、フォアグラウンドの背景画像を割り当てる必要座標ない)より軽量です。

0

最も効果的な方法(メモリとCPU)はpng_set_backgroundを使用して、libPNGはそれをやらせるために、次のようになります。

あなたが必要としない場合、または、あなたが を呼び出すことができ、アルファチャンネルを扱うことができませんpng_set_background()を使用して固定 の色と合成して削除します。これを行うにはpng_set_strip_alpha()を呼び出さないでください。 この画像の透明部分に偽のピクセル値を残します。

png_set_background(png_ptr, &background_color, 
    PNG_BACKGROUND_GAMMA_SCREEN, 0, 1); 

BACKGROUND_COLORはあなたのために生成する データ形式のlibpngに応じてRGBまたはグレースケール値です。

あなたには、いくつかの初歩的なサポートで自分自身にパッチを適用する必要があると思いますので、残念ながら、libpngの周りOpenCVのラッパー(imreadに追加のオプションを渡すために限られた能力によって妨げられる)、これを使用していません。

他の可能な方法は、この特定の目的のためにlibPNGを使用して独自の単純なイメージローダーを作成することです。

いくつかの無駄がある場合は、BGRAとしてロードして、後処理を行います。しかし、私はGabrielで参照されるコードよりもさらに進んで、色変換を組み込んでいます。もちろん

void remove_transparency(cv::Mat const& source 
    , cv::Mat& destination 
    , uint8_t background_color) 
{ 
    CV_Assert(source.type() == CV_8UC4); 

    destination.create(source.rows, source.cols, CV_8UC1); 

    auto it_src(source.begin<cv::Vec4b>()), it_src_end(source.end<cv::Vec4b>()); 
    auto it_dest(destination.begin<uint8_t>()); 

    std::transform(it_src, it_src_end, it_dest 
     , [background_color](cv::Vec4b const& v) -> uchar 
     { 
      // Conversion constants taken from cvtColor docs... 
      float gray(v[0] * 0.114f + v[1] * 0.587f + v[2] * 0.299f); 
      float alpha(v[3]/255.0f); 
      return cv::saturate_cast<uchar>(gray * alpha + background_color * (1 - alpha)); 
     } 
     ); 
} 

、これはそうレバレッジcv::parallel_for_は少しさらにそれを改善するためにしましょう、まだシングルスレッドです。

class ParallelRemoveTransparency 
    : public cv::ParallelLoopBody 
{ 
public: 
    ParallelRemoveTransparency(cv::Mat const& source 
     , cv::Mat& destination 
     , uint8_t background_color) 
     : source_(source) 
     , destination_(destination) 
     , background_color_(background_color) 
    { 
     CV_Assert(source.size == destination.size); 
    } 

    virtual void operator()(const cv::Range& range) const 
    { 
     cv::Mat4b roi_src(source_.rowRange(range)); 
     cv::Mat1b roi_dest(destination_.rowRange(range)); 

     std::transform(roi_src.begin(), roi_src.end(), roi_dest.begin() 
      , [this](cv::Vec4b const& v) -> uint8_t { 
       float gray(v[0] * 0.114f + v[1] * 0.587f + v[2] * 0.299f); 
       float alpha(v[3]/255.0f); 
       return cv::saturate_cast<uint8_t>(gray * alpha + background_color_ * (1 - alpha)); 
      } 
      ); 
    } 

private: 
    cv::Mat const& source_; 
    cv::Mat& destination_; 
    uint8_t background_color_; 
}; 

void remove_transparency(cv::Mat const& source 
    , cv::Mat& destination 
    , uint8_t background_color) 
{ 
    CV_Assert(source.type() == CV_8UC4); 

    destination.create(source.rows, source.cols, CV_8UC1); 

    ParallelRemoveTransparency parallel_impl(source, destination, background_color); 
    cv::parallel_for_(cv::Range(0, source.rows), parallel_impl); 
} 

それはあなたがPythonでこれを必要と判明します。

import numpy as np 
import cv2 

def remove_transparency(source, background_color): 
    source_img = cv2.cvtColor(source[:,:,:3], cv2.COLOR_BGR2GRAY) 
    source_mask = source[:,:,3] * (1/255.0) 

    background_mask = 1.0 - source_mask 

    bg_part = (background_color * (1/255.0)) * (background_mask) 
    source_part = (source_img * (1/255.0)) * (source_mask) 

    return np.uint8(cv2.addWeighted(bg_part, 255.0, source_part, 255.0, 0.0)) 


img = cv2.imread('smile.png', -1) 
result = remove_transparency(img, 255) 

cv2.imshow('', result) 
cv2.waitKey() 
+0

すべての貴重な情報ありがとう。私はPythonの下で働いているので、これを実装することは多少の問題ではないので、私はもっとOpenCVishソリューションを探していたのです。 –

+0

ああ、そうです。あなたのプロフィールに基づいて、私はあなたがC++を望んでいると思っていました:) –

+0

@YvesDaoust Pythonソリューションを追加しました。あなたがはるかに簡単にできることを確信している。 –

関連する問題