スキャナで読み込んだ画像を白黒に完全に二値化するプログラミングを書いています。
python
1img_gauss = cv2.GaussianBlur(self.gray_image(img=img),(1,1),0) 2binary_image = cv2.threshold(img_gauss, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] 3 4photo_size = binary_image.shape[0] * binary_image.shape[1] 5for j in range(binary_image.shape[0]): 6 for k in range(binary_image.shape[1]): 7 if binary_image[j][k] == 255: 8 cnt = cnt + 1 9 10print (cnt / photo_size)
上のプログラムを実行した時、読み込んだ画像が真っ白ならば、最後の行のprintで0が出てきてほしいのですが、現状出てきてくれません。
実際には以下のような二値化した画像が出力されてしまいます。(printの出力とは別で画像を出力している)
これが全てにおいて統一されているのならいいのですが、他の真っ白の画像では以下のようなものが出力されます。
下はそれぞれの読み込んだ元画像です。
真っ白の画像を読み込んだ時に出力結果が0になるような実装の仕方はありますか?
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
下記のような質問は推奨されていません。
- 質問になっていない投稿
- スパムや攻撃的な表現を用いた投稿
適切な質問に修正を依頼しましょう。
回答4件
2
ベストアンサー
cv2.adaptiveThresholdが使える気がします。
関数の入力パラメータを適宜変更し出力画像サンプルを出力生成するシュミレータぽいものを作成するとデバック時に楽です。
昔自作したのを置いておきます。ご参考までに。
2018/03/15追記
入力ソースがスキャナなので、スキャナの機種によってはドロップアウトカラーの設定が行えるかもしれません。マニュアルに書いてあるか一度確認してみてはどうでしょうか。。
Python
1# -*- coding: utf-8 -*- 2import argparse 3import tkinter as tk 4# library 5import cv2 6from PIL import Image, ImageTk 7 8 9class ImageData(object): 10 def __init__(self, src): 11 assert src is not None 12 self.__canvas = src.copy() 13 self.__grayscale = cv2.cvtColor(self.canvas, cv2.COLOR_BGR2GRAY) 14 15 @property 16 def canvas(self): 17 return self.__canvas 18 19 @property 20 def grayscale(self): 21 return self.__grayscale 22 23 24class Application(tk.Frame): 25 def __init__(self, master=None): 26 super().__init__(master) 27 self.data = None 28 self.createWidgets() 29 30 def createWidgets(self): 31 controls = dict() 32 self.topframe = tk.LabelFrame(self, text='params') 33 self.topframe.grid(row=0, column=0) 34 35 controls['ADAPTIVE'] = {'label':'0:MEAN_C / 1:GAUSSIAN_C', 'from_':0, 'to':1, 'length':300, 'orient':tk.HORIZONTAL, 'command':self.__onChanged_ScaleValue} 36 self.scale_adaptive = tk.Scale(self.topframe, controls['ADAPTIVE']) 37 self.scale_adaptive.set(1) 38 self.scale_adaptive.pack() 39 40 controls['THRESHOLDTYPE'] = {'label':'0:BINARY / 1:INV', 'from_':0, 'to':1, 'length':300, 'orient':tk.HORIZONTAL, 'command':self.__onChanged_ScaleValue} 41 self.scale_thresholdType = tk.Scale(self.topframe, controls['THRESHOLDTYPE']) 42 self.scale_thresholdType.pack() 43 # initial stepvalue 3. 44 controls['BLOCKSIZE'] = {'label':'blocksize', 'from_':3, 'to':255, 'length':300, 'orient':tk.HORIZONTAL, 'command':self.__onChanged_ScaleValue} 45 self.scale_blocksize = tk.Scale(self.topframe, controls['BLOCKSIZE']) 46 self.scale_blocksize.set(11) 47 self.scale_blocksize.pack() 48 49 controls['C'] = {'label':'c', 'from_':0, 'to':255, 'length':300, 'orient':tk.HORIZONTAL, 'command':self.__onChanged_ScaleValue} 50 self.scale_c = tk.Scale(self.topframe, controls['C']) 51 self.scale_c.set(2) 52 self.scale_c.pack() 53 54 self.lblimage = tk.Label(self) 55 self.lblimage.grid(row=1, column=0) 56 self.__adaptiveMethod = {0:cv2.ADAPTIVE_THRESH_MEAN_C, 1:cv2.ADAPTIVE_THRESH_GAUSSIAN_C} 57 self.__thresholdType = {0:cv2.THRESH_BINARY, 1:cv2.THRESH_BINARY_INV} 58 59 def draw(self): 60 adaptiveMethod = self.__adaptiveMethod[self.scale_adaptive.get()] 61 thresholdType = self.__thresholdType[self.scale_thresholdType.get()] 62 size = self.scale_blocksize.get() 63 c = self.scale_c.get() 64 # adaptiveThreshold params check 65 # blocksize range:Odd numbers{3,5,7,9,…} intial:3 66 # in:0,0 out:NG blocksize of even. 67 # in:2,0 out:NG blocksize of even. 68 # in:3,10 out:NG size * size - c < 0 69 # in:5,25 out:OK 70 if size % 2 == 0: 71 return 72 if (size * size - c) < 0: 73 return 74 try: 75 result = cv2.adaptiveThreshold(self.data.grayscale, 255, adaptiveMethod, thresholdType, size, c) 76 self.__changeImage(result) 77 except (Exception) as ex: 78 print(ex) 79 pass 80 81 def loadImage(self, src): 82 self.data = ImageData(src) 83 self.__changeImage(src) 84 85 def __changeImage(self, src): 86 #imgtk = ImageTk.PhotoImage(Image.fromarray(cv2.cvtColor(src, cv2.COLOR_BGR2RGB))) 87 imgtk = ImageTk.PhotoImage(Image.fromarray(src)) 88 self.lblimage.imgtk = imgtk 89 self.lblimage.configure(image=imgtk) 90 91 def __onChanged_ScaleValue(self, event): 92 self.draw() 93 94 95def main(): 96 parser = argparse.ArgumentParser(prog='adaptiveThreshold', 97 description='AdaptiveThreshold Simulator') 98 parser.add_argument('--version', action='version', version='%(prog)s 0.0.3') 99 parser.add_argument('--image', '-in', default='c5377162d636f88f9b28215e8e06439b.jpeg') 100 parser.add_argument('--delay', '-d', default='100') 101 args = parser.parse_args() 102 103 print('args:{0}'.format(args)) 104 105 app = Application() 106 app.master.title('AdaptiveThreshold Simulator') 107 app.loadImage(cv2.imread(args.image)) 108 app.pack() 109 app.mainloop() 110 111 112if __name__ == "__main__": 113 main()
投稿2018/03/14 12:25
編集2018/03/14 23:15総合スコア5846
2
大津の二値化を使ってしまうとLouiS0616さんコメントの通り閾値が自動計算されてしまうと思うのですが、白っぽいからといって「それが真っ白」という結論にはできないと思います。
そもそも二値化は「あるパターンがそこにある」という前提で行うものです。そのパターンが画像の特徴「全体的に明るい画像か暗い画像か」にかかわらず「明るいなら明るいなりに、暗いなら暗いなりに」平均的な画素地より明るいか暗いかで二値化するのが大津の二値化の狙いなわけですので、そういう処理の結果をもって実画像から「真っ白」という判断はできないと思います。
cv2.THRESH_OTSUによる二値化ではなく、事前に平均明度を計算し、そこから閾値を定め、あくまでその閾値以上か以下かで二値化するとよいのではないでしょうか?
投稿2018/03/14 11:12
編集2018/03/14 11:14総合スコア18384
下記のような回答は推奨されていません。
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
1
2値化の閾値をもっと上げてみたらどうですか?
投稿2018/03/14 10:08
総合スコア1385
下記のような回答は推奨されていません。
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
2018/03/14 10:10
2018/03/14 10:39
0
真っ白と言っても、実際はノイズが入っているわけですよね。
これに対して大津の二値化をかけると、白に限りなく近い値が閾値となってしまいます。
強引な感がありますが、閾値がある程度255に近いなら真っ白とみなす、とかですかね。
Python
1th, bin_img = cv2.threshold( 2 img, 0, 255, 3 cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU 4) 5if th > 200: 6 bin_img = np.ones(bin_img.shape) * 255
投稿2018/03/14 10:36
編集2018/03/14 10:37総合スコア35632
下記のような回答は推奨されていません。
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
関連した質問
Q&A
解決済
Python whileを一定時間でループする方法
回答1
クリップ0
更新
2023/03/27
Q&A
受付中
Raspberry Pi 4B 無線ルーター化、接続台数について
回答1
クリップ3
更新
2023/03/24
Q&A
解決済
数字群を二つのグループに分けて、それぞれの合計値の差が最小になるアルゴリズムを知りたい。
回答5
クリップ1
更新
2023/03/18
Q&A
解決済
もっと短くすることはできますか?
回答4
クリップ0
更新
2023/03/11
Q&A
解決済
Atcoder ABC294-DのTLEの解消方法を教えてください
回答2
クリップ1
更新
2023/03/22
Q&A
解決済
Nの階乗の末尾に0が何個付くか?という問題の考え方
回答1
クリップ0
更新
2023/03/19
Q&A
解決済
【GAS】特定の値がある列を含んだ行を削除したい
回答3
クリップ1
更新
2023/03/26
Q&A
解決済
音声の離散フーリエ変換後にノイズが入ってしまう
回答3
クリップ2
更新
2023/03/27
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2018/03/14 13:31
2018/03/15 01:55