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

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

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

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

4424閲覧

Saliency Mapの画像を保存したい

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2017/11/22 15:52

編集2017/11/22 15:54

###前提・実現したいこと
こんにちは。
https://github.com/akisato-/pySaliencyMap
上記のサイトで公開されている、
入力した画像をSaliencyMap化するソースコード(main.pyとpySaliencyMap.py)に関して質問させていただきます。

SaliencyMapを作成するにあたって、その過程における画像を保存して仕組みを理解したいと考えております。

以下のソースコードにおける、ICM、CCM、OCMの三つをcv2.imshowしましたが、真っ黒な画像が表示されてしまいました。

それぞれ、色顕著、輝度顕著、方向顕著を示しているので、
下記のような画像が得られると予想したのですが、
解決方法はございますでしょうか。
https://www.dropbox.com/s/02ndfntnjtjlkm9/saliency.png?dl=0

###該当のソースコード

python

1 2#文字数制限を超えてしまうため、pySaliencyMap.pyの前半部分を省略して掲載しております。 3#また、注目していただきたいところを示してあります. 4 5# Name: pySaliencyMap.py 6import cv2 7import numpy as np 8import pySaliencyMapDefs 9#省略あり 10 # feature maps 11 ## constructing a Gaussian pyramid 12 def FMCreateGaussianPyr(self, src): 13 dst = list() 14 dst.append(src) 15 for i in range(1,9): 16 nowdst = cv2.pyrDown(dst[i-1]) 17 dst.append(nowdst) 18 return dst 19 ## taking center-surround differences 20 def FMCenterSurroundDiff(self, GaussianMaps): 21 dst = list() 22 for s in range(2,5): 23 now_size = GaussianMaps[s].shape 24 now_size = (now_size[1], now_size[0]) ## (width, height) 25 tmp = cv2.resize(GaussianMaps[s+3], now_size, interpolation=cv2.INTER_LINEAR) 26 nowdst = cv2.absdiff(GaussianMaps[s], tmp) 27 dst.append(nowdst) 28 tmp = cv2.resize(GaussianMaps[s+4], now_size, interpolation=cv2.INTER_LINEAR) 29 nowdst = cv2.absdiff(GaussianMaps[s], tmp) 30 dst.append(nowdst) 31 return dst 32 ## constructing a Gaussian pyramid + taking center-surround differences 33 def FMGaussianPyrCSD(self, src): 34 GaussianMaps = self.FMCreateGaussianPyr(src) 35 dst = self.FMCenterSurroundDiff(GaussianMaps) 36 return dst 37 ## intensity feature maps 38 def IFMGetFM(self, I): 39 return self.FMGaussianPyrCSD(I) 40 ## color feature maps 41 def CFMGetFM(self, R, G, B): 42 # max(R,G,B) 43 tmp1 = cv2.max(R, G) 44 RGBMax = cv2.max(B, tmp1) 45 RGBMax[RGBMax <= 0] = 0.0001 # prevent dividing by 0 46 # min(R,G) 47 RGMin = cv2.min(R, G) 48 # RG = (R-G)/max(R,G,B) 49 RG = (R - G) / RGBMax 50 # BY = (B-min(R,G)/max(R,G,B) 51 BY = (B - RGMin) / RGBMax 52 # clamp nagative values to 0 53 RG[RG < 0] = 0 54 BY[BY < 0] = 0 55 # obtain feature maps in the same way as intensity 56 RGFM = self.FMGaussianPyrCSD(RG) 57 BYFM = self.FMGaussianPyrCSD(BY) 58 # return 59 return RGFM, BYFM 60 ## orientation feature maps 61 def OFMGetFM(self, src): 62 # creating a Gaussian pyramid 63 GaussianI = self.FMCreateGaussianPyr(src) 64 # convoluting a Gabor filter with an intensity image to extract oriemtation features 65 GaborOutput0 = [ np.empty((1,1)), np.empty((1,1)) ] # dummy data: any kinds of np.array()s are OK 66 GaborOutput45 = [ np.empty((1,1)), np.empty((1,1)) ] 67 GaborOutput90 = [ np.empty((1,1)), np.empty((1,1)) ] 68 GaborOutput135 = [ np.empty((1,1)), np.empty((1,1)) ] 69 for j in range(2,9): 70 GaborOutput0.append( cv2.filter2D(GaussianI[j], cv2.CV_32F, self.GaborKernel0) ) 71 GaborOutput45.append( cv2.filter2D(GaussianI[j], cv2.CV_32F, self.GaborKernel45) ) 72 GaborOutput90.append( cv2.filter2D(GaussianI[j], cv2.CV_32F, self.GaborKernel90) ) 73 GaborOutput135.append( cv2.filter2D(GaussianI[j], cv2.CV_32F, self.GaborKernel135) ) 74 # calculating center-surround differences for every oriantation 75 CSD0 = self.FMCenterSurroundDiff(GaborOutput0) 76 CSD45 = self.FMCenterSurroundDiff(GaborOutput45) 77 CSD90 = self.FMCenterSurroundDiff(GaborOutput90) 78 CSD135 = self.FMCenterSurroundDiff(GaborOutput135) 79 # concatenate 80 dst = list(CSD0) 81 dst.extend(CSD45) 82 dst.extend(CSD90) 83 dst.extend(CSD135) 84 # return 85 return dst 86 ## motion feature maps 87 def MFMGetFM(self, src): 88 # convert scale 89 I8U = np.uint8(255 * src) 90 cv2.waitKey(10) 91 # calculating optical flows 92 if self.prev_frame is not None: 93 farne_pyr_scale= pySaliencyMapDefs.farne_pyr_scale 94 farne_levels = pySaliencyMapDefs.farne_levels 95 farne_winsize = pySaliencyMapDefs.farne_winsize 96 farne_iterations = pySaliencyMapDefs.farne_iterations 97 farne_poly_n = pySaliencyMapDefs.farne_poly_n 98 farne_poly_sigma = pySaliencyMapDefs.farne_poly_sigma 99 farne_flags = pySaliencyMapDefs.farne_flags 100 flow = cv2.calcOpticalFlowFarneback(\ 101 prev = self.prev_frame, \ 102 next = I8U, \ 103 pyr_scale = farne_pyr_scale, \ 104 levels = farne_levels, \ 105 winsize = farne_winsize, \ 106 iterations = farne_iterations, \ 107 poly_n = farne_poly_n, \ 108 poly_sigma = farne_poly_sigma, \ 109 flags = farne_flags, \ 110 flow = None \ 111 ) 112 flowx = flow[...,0] 113 flowy = flow[...,1] 114 else: 115 flowx = np.zeros(I8U.shape) 116 flowy = np.zeros(I8U.shape) 117 # create Gaussian pyramids 118 dst_x = self.FMGaussianPyrCSD(flowx) 119 dst_y = self.FMGaussianPyrCSD(flowy) 120 # update the current frame 121 self.prev_frame = np.uint8(I8U) 122 # return 123 return dst_x, dst_y 124 125 # conspicuity maps 126 ## standard range normalization 127 def SMRangeNormalize(self, src): 128 minn, maxx, dummy1, dummy2 = cv2.minMaxLoc(src) 129 if maxx!=minn: 130 dst = src/(maxx-minn) + minn/(minn-maxx) 131 else: 132 dst = src - minn 133 return dst 134 ## computing an average of local maxima 135 def SMAvgLocalMax(self, src): 136 # size 137 stepsize = pySaliencyMapDefs.default_step_local 138 width = src.shape[1] 139 height = src.shape[0] 140 # find local maxima 141 numlocal = 0 142 lmaxmean = 0 143 for y in range(0, height-stepsize, stepsize): 144 for x in range(0, width-stepsize, stepsize): 145 localimg = src[y:y+stepsize, x:x+stepsize] 146 lmin, lmax, dummy1, dummy2 = cv2.minMaxLoc(localimg) 147 lmaxmean += lmax 148 numlocal += 1 149 # averaging over all the local regions 150 return lmaxmean / numlocal 151 ## normalization specific for the saliency map model 152 def SMNormalization(self, src): 153 dst = self.SMRangeNormalize(src) 154 lmaxmean = self.SMAvgLocalMax(dst) 155 normcoeff = (1-lmaxmean)*(1-lmaxmean) 156 return dst * normcoeff 157 ## normalizing feature maps 158 def normalizeFeatureMaps(self, FM): 159 NFM = list() 160 for i in range(0,6): 161 normalizedImage = self.SMNormalization(FM[i]) 162 nownfm = cv2.resize(normalizedImage, (self.width, self.height), interpolation=cv2.INTER_LINEAR) 163 NFM.append(nownfm) 164 return NFM 165 ## intensity conspicuity map 166 def ICMGetCM(self, IFM): 167 NIFM = self.normalizeFeatureMaps(IFM) 168 ICM = sum(NIFM) 169 return ICM 170 ## color conspicuity map 171 def CCMGetCM(self, CFM_RG, CFM_BY): 172 # extracting a conspicuity map for every color opponent pair 173 CCM_RG = self.ICMGetCM(CFM_RG) 174 CCM_BY = self.ICMGetCM(CFM_BY) 175 # merge 176 CCM = CCM_RG + CCM_BY 177 # return 178 return CCM 179 ## orientation conspicuity map 180 def OCMGetCM(self, OFM): 181 OCM = np.zeros((self.height, self.width)) 182 for i in range (0,4): 183 # slicing 184 nowofm = OFM[i*6:(i+1)*6] # angle = i*45 185 # extracting a conspicuity map for every angle 186 NOFM = self.ICMGetCM(nowofm) 187 # normalize 188 NOFM2 = self.SMNormalization(NOFM) 189 # accumulate 190 OCM += NOFM2 191 return OCM 192 ## motion conspicuity map 193 def MCMGetCM(self, MFM_X, MFM_Y): 194 return self.CCMGetCM(MFM_X, MFM_Y) 195 196 # core 197 def SMGetSM(self, src): 198 # definitions 199 size = src.shape 200 width = size[1] 201 height = size[0] 202 # check 203# if(width != self.width or height != self.height): 204# sys.exit("size mismatch") 205 # extracting individual color channels 206 R, G, B, I = self.SMExtractRGBI(src) 207 # extracting feature maps 208 IFM = self.IFMGetFM(I) 209 CFM_RG, CFM_BY = self.CFMGetFM(R, G, B) 210 OFM = self.OFMGetFM(I) 211 MFM_X, MFM_Y = self.MFMGetFM(I) 212################################################################### 213 # extracting conspicuity maps 214 ICM = self.ICMGetCM(IFM) 215 cv2.imshow('ICM.jpg',ICM) 216 CCM = self.CCMGetCM(CFM_RG, CFM_BY) 217 cv2.imshow('CCM.jpg',CCM) 218 OCM = self.OCMGetCM(OFM) 219 cv2.imshow('OCM.jpg',OCM) 220 MCM = self.MCMGetCM(MFM_X, MFM_Y) 221################################################################### 222 # adding all the conspicuity maps to form a saliency map 223 wi = pySaliencyMapDefs.weight_intensity 224 wc = pySaliencyMapDefs.weight_color 225 wo = pySaliencyMapDefs.weight_orientation 226 wm = pySaliencyMapDefs.weight_motion 227 SMMat = wi*ICM + wc*CCM + wo*OCM + wm*MCM 228 # normalize 229 normalizedSM = self.SMRangeNormalize(SMMat) 230 normalizedSM2 = normalizedSM.astype(np.float32) 231 smoothedSM = cv2.bilateralFilter(normalizedSM2, 7, 3, 1.55) 232 self.SM = cv2.resize(smoothedSM, (width,height), interpolation=cv2.INTER_NEAREST) 233 # return 234 return self.SM

###試したこと
cv2.imshowもcv2.imwriteと同じく、8bitのみしか使用できないのかとも考え
ICM = ICM.astype(np.uint8)
を使って変換しましたが、結果は変わりませんでした。

変換前は、float32でした。

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

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

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

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

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

guest

回答1

0

ベストアンサー

以下、表示に関する部分(動作確認)

■cv2.imshow
少なくともWEBCAMで動かしたときには、投稿内容で問題なく動くことが確認できました。
なので、cv2.imshowまでは問題ないですね。

・動作確認方法
要旨:  pythonを使って画像や動画から「意味ありげな部分」を強調してくり抜くアルゴリズム
検証方法:以下の表に沿ってファイルを用意した後にWEBCAMを繋ぎ、main_webcam.pyを起動
DL元:  akisato-さん@github
必要なファイル:

pythonファイル説明備考
main_webcam.py起動に必要な本体def FMCreateGaussianPyr(略)以降を投稿通りにする
pySaliencyMap.pySaliencyMapのコア-
pySaliencyMapDefs.pyフィルタの定義-

以下、保存に関する部分

■cv2.write
が、cv2.imwriteそのまま保存すると画像が真っ黒になりました。

・対策

原因:  print(OCM.dtype)->float64だと確認できました。
対策:  保存したい画像*255のあとに、uint8に変換
※細かいことは以前の質疑と同じ感じです

中身最小最大
float6464bit浮動小数点数0.000...1.000...
uint8符号なし整数0255

実際のコード:
とりあえずOCMについて書くと以下の感じです。OCMをCCMやICMに変えれば全て行けますね。

Python

1OCM = OCM * 255 2OCM = OCM.astype(np.uint8) 3cv2.imwrite('OCM.jpg',OCM)

投稿2017/11/22 22:15

編集2017/11/22 22:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2017/11/24 15:35

slashさん、ご回答ありがとうございます。 大変お世話になっております。 前回に引き続き、データ型が問題となっていたのですね。 勉強をしたと思っておりましたが、 プログラムが起動したためにOpenCVの設定が原因だと難しく考え、失念しておりました。 プログラミングは、こういった基本に立ち返ることが大切なのだと学ばせていただきました。 ご指導いただき、本当にありがとうございました。
退会済みユーザー

退会済みユーザー

2017/11/24 16:07 編集

いえいえ。 画像処理はあんまり難しく考えるより、画像を見て数値ではなく感性で捉えて、画像が「黒いなー」、paintに突っ込んで塗りつぶすと「真っ黒一色ではなく、真っ黒に近い複数の色からできてるなー」、「floatの0,1問題かなぁ」のように臭い(?)で感じとって進めた方が分かりやすいと思います。
退会済みユーザー

退会済みユーザー

2017/11/24 16:14

連続の投稿申し訳ございません…。 ベストアンサーを付けさせていただいた際は、OCMのみを試して実行結果を見て満足していたのですが、 CCMとICMの場合、同様の手段では画像を得ることはできませんでした。 データ型を解析してみたところ、 ICM…「float32,float32,float32,float32,float32,float32,float32,float64,float64」 CCM… 「float32,float64」 とループのたびにデータ型が変化しているようです。 解決方法はございますでしょうか。 何度もご質問してしまい、申し訳ございません。
退会済みユーザー

退会済みユーザー

2017/11/24 16:22

動かしていないので何とも言えませんが、とりあえずfloat32/64の区別なしにuint8にしてはいかがでしょうか?直観ではいずれも0~1になると思うので、(float*255)-->uint8で行けそうな気がします。取り急ぎダメだったらfloat32/64の型を調べて、型に沿って処理を変えるかだと思います。
退会済みユーザー

退会済みユーザー

2017/11/24 16:23 編集

CCM = CCM.astype(np.float64) CCM = CCM * 255 CCM = CCM.astype(np.uint8) といった形に型を無理やり変化させてみたのですが、やはり真っ黒の画像が出現してしまいました。 感性や匂いでとらえる… プログラミングというものに慣れる必要がありますね。 slashさんのわかりやすい的確なアドバイスは、たゆまぬ努力と経験によって得られたのだと感じます。
退会済みユーザー

退会済みユーザー

2017/11/24 16:40

こちらでも試してみますね。少し時間をください(日曜日くらいまでかかるかもしれません)。 > たゆまぬ努力と経験 そんなかっこいいものではo_0
退会済みユーザー

退会済みユーザー

2017/11/24 16:46

親身に相談にのってくださり、大変感謝しております。 当方もいろいろな試行錯誤を繰り返し、進展があればご報告いたします。 よろしくお願いいたします!!
退会済みユーザー

退会済みユーザー

2017/11/26 02:06

ざーっと試しました。 cv2.equalizeHist()-->階調がつぶれる ○○*64の後にuint8化--->階調がつぶれる(?)振り切って黒くなる 正しいやり方がいまいち浮いて来ませんが、たぶんOpenCVの乗算処理(255で打ち切り)でそれっぽいものは出せそうな気がします。あとはガンマ補正(https://teratail.com/questions/88777の私の回答を見てください)でしょうか。 取り急ぎ連絡まで。
退会済みユーザー

退会済みユーザー

2017/11/26 02:08

https://www.researchgate.net/post/how_to_save_an_image_of_type_float32_in_opencv のPeter Bankheadさんの以下が使えるかもしれません(floatをイメージに) >Try this: >http://www.lfd.uci.edu/~gohlke/code/tifffile.py.html >You can use it directly, or as a plugin to scikit-image: >http://scikit-image.org/docs/0.10.x/api/skimage.io.html#imsave >I did it the latter way, with something like: >if image.dtype == 'float32': > skimage.io.imsave(f_path, image, plugin="tifffile", **kwargs)
退会済みユーザー

退会済みユーザー

2017/11/27 16:24

slashさん、お世話になっております。uppです。 ご連絡が遅れてしまい申し訳ございません。 本日、教えていただいたPeter Bankheadさんの方法を試した結果、 CCMもICMも下記のような理想とする画像を得ることができました。 https://www.dropbox.com/s/f9t2p3c0k1wscnm/rated%20tennis%20hard%20CCM.jpg?dl=0 また、このプログラムを解析していく中でデータ型と関数のルールを改めて振り返ることができました。 ガンマ補正に関してもグラフ込みで説明されていて、理解が進みやすく感じました。 この度は、非常に親身になって問題解決に協力していただき誠にありがとうございます。 また、機会がございましたらどうかよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問