質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

0回答

2422閲覧

【OpenCV】warpAffine関数で透過画像と白背景を重ねた際に、白背景が見えず黒くなってしまう

yamaji1108

総合スコア19

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/04/25 14:50

編集2020/04/25 14:52

前提・実現したいこと

度々失礼いたします。。一昨日もこちらでお世話になりました。
https://teratail.com/questions/255770

iOSアプリで動作する、読み込まれた画像を前景・後景に分離し、後景を(まずは)白い背景にするというプログラムを作っております。

前回はcv::add関数を使い、こちらを実装いたしましたが、今回はcv::warpAffine関数を使い、画像を重ね合わせることでこちらを実装したいです。
主にこちらのサイトを参考にさせていただきました。
https://qiita.com/locutus1990/items/d2d9a68a962b34b62888

下記のような靴の画像(ソースコードでいうと変数sourceMat)に対して実行をしたところ、結果として2枚目のような画像(ソースコードでいうと変数dstImg)が出力されました。

イメージ説明

イメージ説明

下記に該当のソースコードを載せます。(125行目から221行目までが対象となる関数doBlurです。)

私としては、「fgMatはfgMaskにより後景が隠された画像(つまり透過画像)」という認識だったので、白背景の上に重ねれば、当然背景は白になると考えておりました。

私の認識が間違いでしょうか。もし間違いだとすれば、どこの部分を修正すれば、背景を白く出力できるでしょうか。

該当のソースコード

mm

1// 2// OpenCVManager.m 3// Portrait 4// 5// Created by Rina Kotake on 2018/12/01. 6// Copyright © 2018年 koooootake. All rights reserved. 7// 8#import <opencv2/opencv.hpp> 9#import <opencv2/imgcodecs/ios.h> 10 11#import "OpenCVManager.h" 12#import <Foundation/Foundation.h> 13 14@implementation OpenCVManager 15 16//MARK: shared 17static OpenCVManager* sharedData_ = nil; 18 19+ (OpenCVManager*)sharedManager 20{ 21 static dispatch_once_t onceToken; 22 dispatch_once(&onceToken, ^{ 23 sharedData_ = [OpenCVManager new]; 24 }); 25 return sharedData_; 26} 27 28cv::Mat inputMat, maskMat, inpaintMat, blurWithoutGradientMat; 29cv::Mat resultMat, bgModel, fgModel; 30cv::Mat1b fgMaskMat, bgMaskMat; 31 32//MARK: GrabCut 33///前景RectからGrabCutで前景抽出 34-(UIImage*)doGrabCut:(UIImage*)sourceImage foregroundRect:(CGRect)rect iterationCount:(int)iterationCount { 35 //UIImageをMatに変換 36 cv::Mat sourceMat; 37 UIImageToMat(sourceImage, sourceMat); 38 //RGBA > RGB 39 cv::cvtColor(sourceMat , sourceMat , CV_RGBA2RGB); 40 inputMat = sourceMat; 41 //CGRectをRectに変換 42 cv::Rect rectangle(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 43 44 //GrabCut 45 //bgModel, fgMolde: 処理で使用する配列 46 //iterationCount: 処理を繰り返す回数 47 cv::grabCut(sourceMat, maskMat, rectangle, bgModel, fgModel, iterationCount, cv::GC_INIT_WITH_RECT); 48 49 //結果から、前景らしい(GC_PR_FGD)領域を抽出して2値化 50 cv::Mat1b fgMask; 51 cv::compare(maskMat, cv::GC_PR_FGD, fgMask, cv::CMP_EQ); 52 fgMaskMat = fgMask; 53 bitwise_not(fgMaskMat, bgMaskMat); 54 return MatToUIImage(fgMask); 55} 56 57///マーカーマスク画像からGrabCutで前景抽出 58-(UIImage*)doGrabCut:(UIImage*)sourceImage markersImage:(UIImage*)markersImage iterationCount:(int)iterationCount { 59 //新たに入力されたマーカーマスク画像を既存のマスクと合成する 60 cv::Mat1b markersMat = [self synthesizeMaskWithMarkersImage:markersImage]; 61 62 //GrabCut 63 cv::grabCut(inputMat, markersMat, cv::Rect(), bgModel, fgModel, iterationCount, cv::GC_INIT_WITH_MASK); 64 maskMat = markersMat; 65 66 //GC_FGDをGC_PR_FGDに変換 67 cv::MatIterator_<unsigned char> itd = markersMat.begin(); 68 cv::MatIterator_<unsigned char> itd_end = markersMat.end(); 69 for(int i=0; itd != itd_end; ++itd, ++i) { 70 if (*itd == cv::GC_FGD) { 71 *itd = cv::GC_PR_FGD; 72 } 73 } 74 75 cv::Mat1b fgMask; 76 cv::compare(markersMat, cv::GC_PR_FGD, fgMask, cv::CMP_EQ); 77 fgMaskMat = fgMask; 78 bitwise_not(fgMaskMat, bgMaskMat); 79 return MatToUIImage(fgMask); 80} 81 82///マスク組み合わせ 83-(cv::Mat1b)synthesizeMaskWithMarkersImage:(UIImage*)image { 84 //マーカーマスク画像の画素を抽出 85 CGImageRef imageRef = [image CGImage]; 86 NSUInteger width = CGImageGetWidth(imageRef); 87 NSUInteger height = CGImageGetHeight(imageRef); 88 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 89 unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char)); 90 NSUInteger bytesPerPixel = 4; 91 NSUInteger bytesPerRow = bytesPerPixel * width; 92 NSUInteger bitsPerComponent = 8; 93 CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 94 CGColorSpaceRelease(colorSpace); 95 CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 96 CGContextRelease(context); 97 98 //既存のマスクと合成 99 cv::Mat1b markersMat = maskMat; 100 uchar* data = markersMat.data; 101 int countFGD = 0, countBGD = 0, countRem = 0; 102 103 for(int x = 0; x < width; x++) { 104 for( int y = 0; y < height; y++) { 105 NSUInteger byteIndex = ((image.size.width * y) + x ) * 4; 106 UInt8 red = rawData[byteIndex]; 107 UInt8 green = rawData[byteIndex + 1]; 108 UInt8 blue = rawData[byteIndex + 2]; 109 UInt8 alpha = rawData[byteIndex + 3]; 110 if(red == 255 && green == 255 && blue == 255 && alpha == 255) {//白色領域を前景 111 data[width * y + x] = cv::GC_FGD; 112 countFGD++; 113 } else if(red == 0 && green == 0 && blue == 0 && alpha == 255) {//黒色領域を後景 114 data[width * y + x] = cv::GC_BGD; 115 countBGD++; 116 } else { 117 countRem++; 118 } 119 } 120 } 121 free(rawData); 122 return markersMat; 123} 124 125//MARK: Blur 126-(UIImage*)doBlur:(CGFloat)blurSize isUpdatedSegmentation:(BOOL)isUpdatedSegmentation gradientMaskImage:(UIImage*)gradientMaskImage { 127 cv::Mat sourceMat = inputMat; 128 cv::Mat fgMask = fgMaskMat; 129 cv::Mat1b bgMask = bgMaskMat; 130 cv::Mat inpaintingMat; 131 132 if(isUpdatedSegmentation) { 133 //fgマスクの縁を太くする 134 cv::Mat1b fgContoursMask; 135 fgMask.copyTo(fgContoursMask); 136 std::vector<std::vector<cv::Point>> contours; 137 std::vector<cv::Vec4i> hierarchy; 138 cv::findContours(fgContoursMask, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_TC89_L1); 139 cv::drawContours(fgContoursMask, contours, -1, cv::GC_PR_FGD, sourceMat.size().width / 120); 140 141 //Inpainting 自動補間 142 cv::inpaint(sourceMat, fgContoursMask, inpaintingMat, 3, cv::INPAINT_TELEA); 143 inpaintMat = inpaintingMat; 144 } else { 145 inpaintingMat = inpaintMat; 146 } 147 148 cv::Mat blurResultMat, blurMat; 149 double sigumaX = 0;//sigumaX: XYの標準偏差、X=Y=0の時blurSizeから決定する 150 cv::GaussianBlur(inpaintingMat, blurMat, cv::Size(blurSize, blurSize), sigumaX, sigumaX, cv::BORDER_REPLICATE); 151 blurWithoutGradientMat = blurMat; 152 153 154 if (gradientMaskImage) { 155 //グラデーションマスクを変換 156 cv::Mat gradientMaskMat; 157 UIImageToMat(gradientMaskImage, gradientMaskMat); 158 cv::cvtColor(gradientMaskMat , gradientMaskMat , CV_RGBA2GRAY); 159 bitwise_not(gradientMaskMat, gradientMaskMat); 160 161 //グラデーションマスクとBlur画像を合成 162 blurResultMat = cv::Mat(sourceMat.size(), sourceMat.type()); 163 for (int y = 0; y < blurResultMat.rows; ++y) { 164 for (int x = 0; x < blurResultMat.cols; ++x) { 165 cv::Vec3b pixelOrig = sourceMat.at<cv::Vec3b>(y, x); 166 cv::Vec3b pixelBlur = blurMat.at<cv::Vec3b>(y, x); 167 float blurVal = gradientMaskMat.at<unsigned char>(y, x) / 255.0f; 168 cv::Vec3b pixelOut = blurVal * pixelBlur + (1.0f - blurVal) * pixelOrig; 169 blurResultMat.at<cv::Vec3b>(y, x) = pixelOut; 170 } 171 } 172 } else { 173 blurResultMat = blurMat; 174 } 175 176// //↓追加した文 177// int cols = blurResultMat.cols; 178// int rows = blurResultMat.rows; 179// for (int j = 0; j < rows; j++) { 180// for (int i = 0; i < cols; i++) { 181// blurResultMat.at<cv::Vec3b>(j, i)[0] = 255; //青 182// blurResultMat.at<cv::Vec3b>(j, i)[1] = 255; //緑 183// blurResultMat.at<cv::Vec3b>(j, i)[2] = 255; //赤 184// } 185// } 186// //↑追加した文 187 188 189 //合成 190 cv::Mat bgMat, fgMat, result; 191 192 NSString *path = [[NSBundle mainBundle] pathForResource:@"白背景" ofType:@"png"]; 193 cv::Mat whtimg = cv::imread([path UTF8String], cv::IMREAD_COLOR); 194 resize(whtimg,whtimg,sourceMat.size(),1); 195// NSString *path2 = [[NSBundle mainBundle] pathForResource:@"キャット" ofType:@"png"]; 196// cv::Mat catimg = cv::imread([path2 UTF8String], cv::IMREAD_ANYCOLOR); 197 198 //whtimg.copyTo(bgMat, bgMask); 199 sourceMat.copyTo(fgMat, fgMask); 200 201 //↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓追加した文↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 202 203 //背景画像の作成 204 cv::Mat dstImg; 205 whtimg.copyTo(dstImg); 206 //前景画像の変形行列 207 cv::Mat mat1 = (cv::Mat_<double>(2,3)<<1.0, 0.0, 0.0, 0.0, 1.0, 0.0); 208 //アフィン変換の実行(前景画像fgMatを白背景に重ねる) 209 cv::warpAffine(fgMat, dstImg, mat1, dstImg.size(), CV_INTER_LINEAR, cv::BORDER_TRANSPARENT); 210 211 //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑追加した文↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 212 213 //cv::add(bgMat, fgMat, result); 214 215 //DOF比較用 216 cv::Mat bgWithoutGradientMat; 217 blurMat.copyTo(bgWithoutGradientMat, bgMask); 218 cv::add(bgWithoutGradientMat, fgMat, blurWithoutGradientMat); 219 220 return MatToUIImage(dstImg); 221} 222 223 224-(UIImage*)inpaintingImage { 225 cv::Mat inpaintingMat = inpaintMat; 226 return MatToUIImage(inpaintingMat); 227} 228 229-(UIImage*)blurWithoutGradientImage { 230 cv::Mat blurMat = blurWithoutGradientMat; 231 return MatToUIImage(blurMat); 232} 233 234//MARK: reset 235-(void)resetManager { 236 maskMat.setTo(cv::GC_PR_BGD); 237 bgModel.setTo(0); 238 fgModel.setTo(0); 239} 240 241@end 242

試したこと

上記のソースコードで、fgMatの代わりに猫の画像(catimg、背景は透過されている)で実行した際は、白背景の画像が出力されましたが、猫の色が若干変化しております。。
イメージ説明
↑が元画像
![イメージ説明]
↑が出力画像(スクリーンショットにしております)

補足情報(FW/ツールのバージョンなど)

Xcode Version 10.3 (10G8)
iOS 12.4.6
Swift Version 5.0.1
OpenCV 3.4.10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問