🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

Q&A

解決済

1回答

3527閲覧

画像処理の鮮鋭化フィルタ適用後の0~255から外れた画素値の補正方法を知りたい

reishisu

総合スコア44

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

0グッド

0クリップ

投稿2019/12/31 16:54

編集2019/12/31 17:32

前提・実現したいこと

現在、Python3で画像処理の鮮鋭化を勉強しております。
その中で、鮮鋭化フィルタをかけた際に0~255の値から外れた値が出てきました。

色々なサイトをみて回ったものの0~255以外をカットする方法しか見当たらなく、強制的に丸める方法で実装していましたが、鮮鋭化フィルタにかける定数倍の値を大きくするとかなり汚くなりました。

そこで、全体を同比補正するために画素の配列をフィルタ適用後、全体に最小値の分だけ足して全体に、255/abs(max-min)をかけて0~255に収まるよう補正しましたがこちらも定数倍の値を大きくする度に、鮮鋭化は強くなってる気はするのですがそれ以上に画像が潰れて汚くなってしまいました。

なので、自力で実装したいのでOpenCVやPILのImageFilterなどの画像処理ライブラリは使わない方法で、他に良い方法があれば教えて頂きたいです。

発生している問題・エラーメッセージ

実行結果

k=4, 最小値:-270.1111111111111, 最大値:636.9999999999999 k=9, 最小値:-648.0, 最大値:1142.0 k=18, 最小値:-1344.0, 最大値:2051.0

元画像
original
k=4の時
k=4
k=9の時
k=9
k=18の時
k=18

該当のソースコード

Python3

1import numpy as np # 行列の計算用 2from PIL import Image # 画像の読み込み用 3 4# 元画像を読み込む 5image = Image.open('gray02.jpg') 6# 元の画像 7image.convert("L").show() 8 9############################################### 10# 鮮鋭化を行う関数 11# 12# @param int size 鮮鋭化フィルタのサイズ 13# @param int k 入力画素-平滑化画素にかける定数倍の値 14############################################### 15def sharpening_filter(size=3, k=4): 16 17 image_array = np.array(image.convert("L")) # 元画像 18 sharp_image_array = np.array(image.convert("L"), dtype='float64') # 元画像 19 20 ######################### 21 # 鮮鋭化を行う 22 ######################### 23 # 色々と使うので先にずらす値を変数として作っておく 24 slide = int(size/2) 25 # 平均化フィルタ 26 avg_filter = np.full((size, size), 1/size**2) 27 # 入力画素だけ出力するフィルタ 28 input_filter = np.zeros((size, size)) 29 input_filter[slide][slide] = 1 30 # 鮮鋭化フィルタ 31 sharp_filter = input_filter + (k * ( input_filter - avg_filter )) 32 33 min = 0 # 最小値 34 max = 0 # 最大値 35 36 # 鮮鋭化の処理を行う 37 # 縦にかけるループ 38 for row_index in range(slide, len(image_array)-slide): 39 # 横にかけるループ 40 for column_index in range(slide, len(image_array[row_index])-slide): 41 # 注目画素を新しいくするために、一旦0クリアする 42 new_pixel_value = 0 43 # 注目画素と周囲の画素にフィルタをかけて積和の値で画素を更新する 44 # 行列を横1列に変換する 45 input_temp = image_array[row_index-slide:row_index+slide+1, column_index-slide:column_index+slide+1].ravel() 46 sharp_temp = sharp_filter.ravel() 47 # 変換した行列の積和をとる 48 new_pixel_value = np.sum( np.multiply(input_temp, sharp_temp) ) 49 # 最小値・最大値の比較を行う 50 min = min if min < new_pixel_value else new_pixel_value 51 max = max if max > new_pixel_value else new_pixel_value 52 # 適用後の値で更新する 53 sharp_image_array[row_index][column_index] = new_pixel_value 54 55 # 最小値と最大値を表示する 56 print("k={0}, 最小値:{1}, 最大値:{2}".format(k, min, max)) 57 58 delta = abs(max - min) # 最大値と最小値の幅 59 mag = 255 / delta # 補正するための倍率 60 61 # 縦にかけるループ 62 for row_index in range(slide, len(image_array)-slide): 63 # 横にかけるループ 64 for column_index in range(slide, len(image_array[row_index])-slide): 65 # minの値分だけずらして最小値を0にする 66 temp = sharp_image_array[row_index][column_index] + abs(min) 67 # 0~255に収まるようにする 68 temp *= mag 69 # 値を更新 70 sharp_image_array[row_index][column_index] = temp 71 72 # フィルタリングした画像にする 73 sharp_image = Image.fromarray(np.uint8( sharp_image_array ) ) 74 # フィルタリングした変換結果を表示する 75 sharp_image.show() 76 77# 鮮鋭化を行う 78sharpening_filter(3, 4) # k = 4 79sharpening_filter(3, 9) # k = 9 80sharpening_filter(3, 18) # k = 18

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

Python 3.8.0
Numpy 1.17.4
PIL 6.2.1

追記

ソースコードを見るとわかると思いますが、フィルタのかけられない画像の端の方などはそのまま出力するようにしております。

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

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

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

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

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

meg_

2019/12/31 17:40

先鋭化フィルタとは「cv2.filter2D()」のことでしょうか?
退会済みユーザー

退会済みユーザー

2019/12/31 18:43 編集

> OpenCVやPILのImageFilterなどの画像処理ライブラリは使わない方法で、他に良い方法があれば OpenCVのやり方ではありますが、 img = cv2.imread("img.jpeg") img_blur = cv2.GaussianBlur(img,(5,5),0) img_unsharp = cv2.addWeighted(img,1.5,img_blur,-0.5,0) cv2.imshow("img_unsharp (OpenCV)",img_unsharp) cv2.waitKey(0) のような感じでアンシャープマスクをすると綺麗に鮮鋭化できます。 (が、これをNumpyで書き直すのは骨が折れそうです…)
reishisu

2019/12/31 19:09

おお〜、スッキリとしたコードですごいですね! そうなんですよね。。。 個人的に、フィルタ適用のブラックボックスになっている畳み込みの処理や範囲外のアルゴリズムを自力で実装したかったのですが、やはり厳しいのでしょうか...><
guest

回答1

0

ベストアンサー

所定の範囲を超えた値について、最小値~最大値が0~255になるようにするということはエッジが強ければ強いほど必然的にコントラストは下がります。

私が思うにこれは考え方の問題で「鮮鋭化フィルタの実装は既にできている」のだと思います。
どういうことかと言いますと「0255以外をカットする」「0255に収まるよう補正する」というのは、どちらもフィルタ結果の分析方法の問題であって、鮮鋭化フィルタとは別課題として扱うべきです。
一般的なライブラリでは画像として保存する都合上、何かしらの形で0~255に納めなければならず、その際元の画像のコントラストを維持するために範囲外の値をカットしていると思われますが、鮮鋭化フィルタ自体は0~255範囲外の値を含む結果で正しいのです。

「0255以外をカット」は、元の画像のコントラストを維持しつつエッジ強度を見る目的に合致します。
「min~maxを0
255に収まるよう補正」は、全体のエッジ強度の比率が見たいときには適しています。
min, maxに限らず「XX~XXの範囲を0~255に収まるように補正」すれば、目的のエッジ強度範囲にのみ着目することができます。

目的に応じて使い分けが必要であり、これは別に鮮鋭化フィルタの本質ではないので、自前で作るときは別物として考えて良いかと思います。

投稿2019/12/31 20:01

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

reishisu

2019/12/31 20:28

回答して頂きありがとうございます! フィルタ結果の分析方法の問題と言うことで、かなり腑に落ちました!! 確かにそう言われてみれば、私の買った参考書だとフィルタのアルゴリズムは乗っていましたが、どの様にして範囲外の値を処理するかまでは言及されておりませんでした。 しかしながら、参考書だとkの値を18まで上げても綺麗に鮮鋭化されていたので、鮮鋭化=必ず綺麗にくっきり映るものと勘違いしておりました...(参考書の元画像はかなり暗めの画像だったかもしれないです) 参考書やどこのサイトも綺麗な実行結果ばかりで、周りに聞けなかったのでとても助かりました>< なので、一旦鮮鋭化の方は終えて次の章に進み一通り終わったらもう一度分析方法について自分で考えてみようと思います! 改めて、回答して頂きありがとうございました????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問