前提
opencvを使っております。
画像をモノクロ化して、jpegとして保存を行っています。
実現したいこと
・画像のサイズ(xxxピクセル、yyyピクセル)は維持
・圧縮率はできるだけ上げない(拡大したときの画質を維持)
・グレースケールにして、ファイル容量を半分など、できるだけ落とす
発生している問題・エラーメッセージ
opencvで試しては見たのですが、ファイルの容量が下がりません。
おそらく、rgbの数値を入れる配列情報が残ったままになっているのでしょうか。
Photoshopでも同様のことをやってみましたが、グレースケールにして保存すると、ファイルサイズが小さくなっていることが確認できます。
Photoshopでやるような感じで、ファイルサイズを小さくできる方法をご存じであれば、教えていただけないでしょうか?
# ライブラリのインポート import cv2 # 画像の読み込み img = cv2.imread('data/src/lena.jpg') # 読み込んだ画像をグレースケール化 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 画像の保存 cv2.imwrite('/etc/tmp/after_Lena.jpg', img_gray)
OpenCVの imwrite API仕様を見る限り、グレイスケール保存には対応しないようです。そのようなオプション指定も存在しません。
https://docs.opencv.org/4.6.0/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce
https://docs.opencv.org/4.6.0/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac
単にGrayscale JPEGへとファイル変換したいだけであれば、ImageMagickツールなどの利用を検討されてはいかがでしょう。
https://devlights.hatenablog.com/entry/2021/08/26/153124#24bit-JPEG-%E3%82%92-8bit-Grayscale-JPEG-%E3%81%B8
> rgbの数値を入れる配列情報が残ったままになっているのでしょうか。
そうはなってないはずです
コードの最後に
print(img.shape)
print(img_gray.shape)
を追加して実行したら分かりますが、「img_gray」は次元が2次元に減ってます(カラー情報が無くなってます)
「cv2.imwrite()」では、データ(numpy配列)のshapeが「(縦, 横)」の場合はグレースケールで、「(縦, 横, 3)」の場合はカラーで保存されますので、「img_gray」を保存した「after_Lena.jpg」は、グレースケール画像のファイルのはずです
コードの最後に
cv2.imwrite('/etc/tmp/before_Lena.jpg', img)
を追加して実行して、カラーのままのデータも保存して、「after_Lena.jpg」と「before_Lena.jpg」のサイズを比べてみてください
カラーの「before_Lena.jpg」の方がファイルのサイズが大きくないですか?
また、カラーで保存し直しただけの「before_Lena.jpg」は、オリジナルの「lena.jpg」よりもファイルのサイズが大きくないですか?
上記のようにして、もし「before_Lena.jpg」の方が「lena.jpg」よりもファイルのサイズが大きいなら、
> 圧縮率はできるだけ上げない
が、「圧縮率を下げる」(あまり圧縮しない)になってるのでしょう
その場合は、「cv2.imwrite()」で品質を指定して、「before_Lena.jpg」のサイズが「lena.jpg」と同じくらいになれば、圧縮率が「lena.jpg」とだいたい同じになると思いますので、それと同じ品質を指定して保存した「after_Lena.jpg」のサイズは、「lena.jpg」よりも小さくなるでしょう
参考
https://note.nkmk.me/python-opencv-imread-imwrite/
の「cv2.imwrite()で画像ファイルに保存」
yohhoyさん
ありがとうございます。PYTHON上でコマンドとして実行する分としてはいいですね。
windowsで、mobaxtermの場合、pipなどの問題が絡み、少し扱いにくいように感じました。
jbpb0さん
>を追加して実行したら分かりますが、「img_gray」は次元が2次元に減ってます(カラー情報が無くなってます)
なるほど、確かにファイル容量はすこーしだけ、減少しているのは知っていたのですが、配列も変化はしていたのですね。していないと勘違いしておりました。
>また、カラーで保存し直しただけの「before_Lena.jpg」は、オリジナルの「lena.jpg」よりもファイルのサイズが大きくないですか?
これも、デフォルトで圧縮率が30%ぐらいと体感的には感じております。
ですので、圧縮率を50や、95などにすると、やはりもとのファイルよりも容量が大きくなってしまうようですね。
圧縮率について、大小と容量の大小を勘違いしており、すいません。たしかにjbpb0さんの言う通りですね。
先に書いたことと重複しますが、解像度(縦横の画素数)を変えずにカラーのままで保存した場合に、元の画像ファイルとサイズがだいたい同じになる「品質」に設定しないと、
> 圧縮率はできるだけ上げない(拡大したときの画質を維持)
にはなりません
そのように「品質」を設定した上で、グレースケールで保存したら、ファイルのサイズは元画像よりも小さくなるでしょう
どんなツールを使おうとも、上記は共通だと思います
> ファイル容量はすこーしだけ、減少している
ということであれば、それが限度なのでしょう。
カラーをグレイスケールにしたところで劇的にファイル容量が少なくなるわけではありません。画像の内容や画質によりますが、せいぜい1割か2割減といったところです。
また、「グレイスケールJPEGで保存した画像」と比べて「カラーJPEGで保存した、内容はグレースケールの画像」は容量はほとんど増えません。試した範囲では2%~4%差でした。
OpenCVでグレイスケールJPEGが利用できないのかは分かりませんが、仮にカラーJPEGで保存されていたとしてもさほど状況に違いはありません。
> yohhoyさん
ImageMagickツールを試しましたが、やはり小さくならないようです。
> ikadzuchiさん
確かに体感的に1-2割が限度と感じています。
opencvでのjpeg保存の「品質」(大きいほど画質がいい=圧縮しない)は、範囲が0〜100で、指定しないと95だそうです
95は上限100に近いので、デフォルト設定では、圧縮はかなり控えめですよね
https://tat-pytone.hatenablog.com/entry/2021/04/25/114334
上記Webページの、「品質」を変えて保存した画像ファイルのサイズ比較の表によると、「品質」を80から40に変えたら、ファイルサイズは約半分になってます
「品質」設定は、結構ファイルサイズに効くようです
元画像(lena.jpg)の圧縮が、もし「品質」95よりもかなり小さい(高圧縮)数値相当の圧縮がされてるのなら、それに合わせて「品質」を設定して画像保存しないと、質問者さんが意図してるような結果にはなりませんよね
質問者さんが使ってる画像とは違うかもしれませんが、
http://icb-lab.naist.jp/members/yoshi/ouec_lecture/image_recognition/
の「演習教材」の「"Lena" image」の「len_std.jpg」
http://icb-lab.naist.jp/members/yoshi/ouec_lecture/image_recognition/image_files/len_std.jpg
をダウンロードして、試してみました
以下、opencvのjpeg保存の「品質」を設定しない場合の、ファイルサイズ(byte)です
・元画像:11888
・読み込んで保存(カラー):22611
・読み込んでグレースケール変換して保存:19443
カラーのままでサイズが元画像の2倍くらいになってるので、グレースケールでもまだサイズ大きいですね
「品質」70で保存したら、カラーで保存した場合のファイルサイズがだいたい同じになりました
・元画像:11888
・読み込んで保存(カラー):11973
・読み込んでグレースケール変換して保存:10219
グレースケールのサイズは元画像の86%くらいになり、一応サイズは小さくなりましたが、
> 体感的に1-2割が限度と感じています。
ですね
情報ありがとうございます。
圧縮率ですが、大体の目安として
幅*高さ*3
とファイルサイズbyteを比較して、大きく離れているほど、圧縮されているという感じのようです。

回答1件
あなたの回答
tips
プレビュー