OpenCVの(BGR)に悩む方へ

## はじめに: OpenCVにおける画像の色情報処理について

OpenCVでは色情報をBGRの順番で扱っています。これは、例えばimg.shape = (1920,1080,3)のようなカラー画像を取り扱う場合に、3チャンネル目がBGR（青、緑、赤）の順番で保存されていることを意味します。したがって、cv2.imread()関数を用いて画像を読み込む際には、色情報は自動的にBGR形式で取得されることになります。

このBGR形式は、他の一般的な画像処理ライブラリやツールがRGB形式を使用することとは対照的です。このため、OpenCVを使用する際は、この色情報の取り扱いに特に注意が必要です。

### 問題になるケース
前述の通り、OpenCVは色情報をBGRの順で処理しますが、Pillow、Matplotlib、Tkinterなどの他の一般的な画像処理ライブラリやツールはRGB順で色情報を扱います。この違いが問題となる主なケースは、OpenCVとこれらの他のライブラリを併用する場合です。特に、画像の表示や変換を行う際に色の不整合が生じやすくなります。

例えば、OpenCVで画像を読み込んだ後、それをPillowやMatplotlibで扱う場合、画像の色が予期せず変わることがあります。この問題に対処するためには、画像データをBGRからRGBに変換する必要があります。この変換は、OpenCVのcv2.cvtColor関数を使って簡単に行うことができます。

詳しい例や解説は、以下のリンクでご確認いただけます。
https://qiita.com/Daiki_P/items/e2a67be67992783ef2e2

### Pythonを用いた画像処理におけるOpenCVとPillowの基本的なデータ処理の違いに関する概要

* OpenCVの画像データ処理:
1. OpenCVでは、画像データはnumpyの配列（numpy array）として扱われます。
1. この配列は、画像の各ピクセルの色情報を含む多次元配列で、主にBGR形式（青、緑、赤）で色情報が格納されています。

* Pillowの画像データ処理:
1. Pillowでは、画像はPillowのImageオブジェクトとして扱われます。
1. Pillowは主にRGB形式（赤、緑、青）で色情報を扱い、Pythonにおける画像処理や画像操作のための高レベルインターフェースを提供します。

* numpy arrayとImage Objectの相互変換:
1. OpenCVのnumpy arrayとPillowのImage Object間の変換は可能です。
1. この変換機能により、両ライブラリの機能を柔軟に組み合わせて使用することができます。
1. ただし、変換時には色情報の形式（BGRとRGB）の違いに注意する必要があります。
Pythonでの画像処理におけるこれらのライブラリの使い分けと組み合わせは、柔軟な画像処理と効率的な開発を実現します。特定の処理や要件に応じて最適なライブラリや方法を選択することが重要です。

## Lena画像にGaussian Blurフィルタを適用する実験

Lenaの画像を読み込み、Gaussian Blurフィルタを掛けて、その結果を保存します。
![lena.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/9b1409f2-3d27-e168-5241-f38a1346c70d.png)
Fig origina lena.png

![lena_blurred.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/a6172981-ec06-c58a-95de-893d5502cce5.png)
Fig blurred lena.png


### Pure OpenCV
* 入力 (cv2.imread):
1. cv2.imread()関数を使用して画像を読み込むと、その画像は自動的にBGR（青、緑、赤）の順でnumpy配列に保存されます。
1.この特性は、OpenCVの標準的な色情報の処理方法です。

* 表示 (cv2.imshow):
1. cv2.imshow()関数により画像を表示する際、画像がBGR順であることを前提としています。
1. このため、OpenCVで読み込んだ画像は、特に変換処理を行わなくても、この関数を使用して正しく表示されます。

* 出力 (cv2.imwrite):
1. cv2.imwrite()関数を使用して画像をファイルに保存する際には、画像がBGR順であることが前提となっています。
1. この関数は、BGR順のnumpy配列を受け取り、それをファイルに正しく保存します。

OpenCVを使用する際、これらの特性を理解しておくことが重要です。特に他のライブラリ（RGB順で処理するもの）と組み合わせて使用する場合は、色情報の順序に注意する必要があります。

```python:
import cv2

# 画像ファイルのパス
image_path = "./image/lena.png"
output_path = "./result/lena_blurred.png"

# 画像を読み込む
img = cv2.imread(image_path)

# 画像の形状を表示する（デバッグ用）
print("Original image shape:", img.shape)

# ガウシアンブラーを適用する
blur_kernel_size = (11, 11)  # ブラーのカーネルサイズ
blur_sigma = 1  # ガウシアンブラーのシグマ値
img_blur = cv2.GaussianBlur(img, blur_kernel_size, blur_sigma)

# オリジナル画像とブラー適用後の画像を表示
cv2.imshow("Original Lena", img)
cv2.imshow("Blurred Lena", img_blur)

# ブラー適用後の画像をファイルに保存
cv2.imwrite(output_path, img_blur)

# キー入力を待ち、すべてのウィンドウを閉じる
cv2.waitKey(0)
cv2.destroyAllWindows()

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/324eae25-b4a0-12a5-1fd0-e228b15891e5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/479db775-3f69-69d4-e66d-faddbc8d2ba0.png)



### Pillow + OpenCV
* 画像の読み込み (cv2.imread):
1.最初に、cv2.imread()関数を使用して画像を読み込みます。この時点での画像はBGR形式のnumpy配列として保存されます。

* BGRからRGBへの変換:
1. OpenCVのcv2.cvtColor()関数を使用して、読み込んだ画像をBGRからRGB形式に変換します。
1. この変換は、cv2.COLOR_BGR2RGBオプションを用いて行います。

* Gaussian Blurの適用:
1. 変換されたRGB画像に対して、cv2.GaussianBlur()関数を用いてガウシアンブラー（ぼかし）を適用します。

* Pillowを使った画像の表示:
1. OpenCVのcv2.imshow()の代わりに、PillowのImage.show()メソッドを使用して画像を表示します。
1. このためには、変換されたnumpy配列をPillowのImageオブジェクトに変換する必要があります。これは、PillowのImage.fromarray()関数を使用して行います。

この方法のポイントは、途中で画像をRGBに変換し、その後Pillowで処理することです。これにより、Pillowの機能を活用しながら、OpenCVで読み込んだ画像データを適切に扱うことができます。

```python:
import cv2
from PIL import Image

# 画像ファイルのパス
image_path = "./image/lena.png"
output_path_cv2 = "./result/lena_cv2.png"
output_path_pillow = "./result/lena_pillow.png"

# 画像を読み込む
img_bgr = cv2.imread(image_path)

# BGRからRGBに変換
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# ガウシアンブラーを適用する
blur_kernel_size = (11, 11)  # ブラーのカーネルサイズ
blur_sigma = 1  # ガウシアンブラーのシグマ値
img_blur_rgb = cv2.GaussianBlur(img_rgb, blur_kernel_size, blur_sigma)

# PillowのImageオブジェクトに変換
img_pillow = Image.fromarray(img_blur_rgb)

# Pillowを使って画像を表示
img_pillow.show()

# オリジナル画像とブラー適用後の画像を表示
cv2.imshow("Original Lena", img_bgr)

# ブラー適用後の画像をファイルに保存
cv2.imwrite(output_path_cv2, img_bgr)

# キー入力を待ち、すべてのウィンドウを閉じる
cv2.waitKey(0)
cv2.destroyAllWindows()


```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/2e710c01-976b-fe67-64e6-56c816445c4a.png)
Pillowのshow()は、外部プログラムを利用して表示します。

### 画像処理におけるPillowとOpenCVのベストプラクティス

画像処理におけるPillowとOpenCVの使用に関するベストプラクティスについて、以下にご説明いたします。

* **画像の入力、出力、表示にPillowの使用:**

1. 画像の入力と出力、および表示にはPillowを使用することが推奨されます。
1. PillowはRGB色順を使用するため、色情報の整合性が保たれ、他のライブラリとの互換性が高まります。
1. 特に、TkinterのCanvasなどで画像を表示する場合、Pillowを使用することで扱いやすくなります。

* **内部のフィルタ処理にはOpenCVの使用:**

1. 画像のフィルタ処理や高度な画像操作には、OpenCVの機能を利用することが有効です。
1. OpenCVを使用する際、必要に応じてBGRからRGBへの変換を行うことができます。
1. この変換を行うことで、OpenCVの強力な画像処理機能とPillowの画像入出力機能の利点を組み合わせることが可能です。

* **OpenCVのimwriteの日本語サポートの問題:**

1. OpenCVのimwrite()関数は、日本語を含む2バイト文字のファイル名をサポートしていません。
1. このため、ファイル名に日本語を使用する場合は、Pillowの保存機能を使用することでエラーを回避できます。

以上のベストプラクティスに従うことで、画像処理の流れがよりスムーズになり、予期せぬ問題を避けることができます。さらに、画像処理における色情報の整合性を保ちながら、OpenCVの高度な機能も活用することが可能になります。

```python:
import cv2
import numpy as np
from PIL import Image

# 画像ファイルのパス
image_path = "./image/lena.png"
output_path_pillow = "./result/lena_blur_pillow.png"

# 画像を読み込む
img_pillow = Image.open(image_path)
# PillowのImageオブジェクトをNumPy配列に変換
img_rgb = np.array(img_pillow)


# ガウシアンブラーを適用する
blur_kernel_size = (11, 11)  # ブラーのカーネルサイズ
blur_sigma = 1  # ガウシアンブラーのシグマ値
img_blur_rgb = cv2.GaussianBlur(img_rgb, blur_kernel_size, blur_sigma)

#Numpy配列をPillowのImageオブジェクトに変換
img_blur_pil = Image.fromarray(img_blur_rgb)
# Pillowを使って画像を表示
img_blur_pil.show()
# ブラー適用後の画像をファイルに保存
img_blur_pil.save(output_path_pillow)


```


## 参考資料

https://qiita.com/Daiki_P/items/91acd5cc208fedd16ee9