VS Codeでvenvがうまく動作しなくなった話

結論 venvをあきらめて、Pipenvを導入すればなぜか解決した。 経緯 Pythonの開発環境にVS Codeを使っていましたが、ある日突然、venvで作った環境が見えなくなりました。 PowerShellからは切り替えができるので、venv自体は正しく動いているようでした。 PythonとVS Codeをクリーンインストールしても状況は変わりませんでした[1]。 Pipenvの使い方 最近はPipenvというものがあるらしいので、それを導入することとしました[2][3]。 pip install pipenv 以下のように環境変数を設定することで、プロジェクトのフォルダ直下に仮想環境を構築してくれます。 PIPENV_VENV_IN_PROJECT=true VS Code上にフォルダを作成し、その直下で仮想環境を作成します。 コマンドはVS Code上のPowerShellで行いました。 例えば以下のようになります。パスやPythonのバージョンはご自身の環境に合わせてください。 *pythonの後に半角スペースがあるのでうっかり詰めないでください。 *venvファイルが作成されるという情報もありますが、私の場合はPipfileのみ作られました。 PS PS C:\Users\User Name\Documents\CODE\Python\Test> pipenv install --python 3.8 VS Code上でF1キーを押して、「reload」を検索して実行します。 これで左下のPythonのバージョンセレクトから環境選択できるはずです。 仮想環境から抜けるときは以下のコマンドを使います。 deactivate 参考文献 [1] sota0726 「VScodeを完全にアンインストールする方法(windows10)「拡張機能のホストが予期せずに終了しました。」を改善するために」閲覧日:2020/09/13 https://www.atmarkit.co.jp/ait/articles/1810/12/news026.html [2] KRiver1 「pyenv、pyenv-virtualenv、venv、Anaconda、Pipenv。私はPipenvを使う。」閲覧日:2020/09/13 h

Python版OpenCVで色抽出を行う

今回は,Python版のOpenCVを使ってHSV色空間で色抽出をする方法をメモしておきます.

環境は以下のとおりです.
Python 2.6
OpenCV 2.4.6

更新履歴
  • 2015/03/12
    しきい値処理におけるTHRESH_BINARYとTHRESH_BINARY_INVが逆になっているのを修正しました.

それでは早速スクリプトを見ていきます.

import cv2

def extract_color( src, h_th_low, h_th_up, s_th, v_th ):

    hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
    h, s, v = cv2.split(hsv)

    if h_th_low > h_th_up:
        ret, h_dst_1 = cv2.threshold(h, h_th_low, 255, cv2.THRESH_BINARY) 
        ret, h_dst_2 = cv2.threshold(h, h_th_up,  255, cv2.THRESH_BINARY_INV)
        
        dst = cv2.bitwise_or(h_dst_1, h_dst_2)

    else:
        ret, dst = cv2.threshold(h,   h_th_low, 255, cv2.THRESH_TOZERO) 
        ret, dst = cv2.threshold(dst, h_th_up,  255, cv2.THRESH_TOZERO_INV)

        ret, dst = cv2.threshold(dst, 0, 255, cv2.THRESH_BINARY)
        
    ret, s_dst = cv2.threshold(s, s_th, 255, cv2.THRESH_BINARY)
    ret, v_dst = cv2.threshold(v, v_th, 255, cv2.THRESH_BINARY)

    dst = cv2.bitwise_and(dst, s_dst)
    dst = cv2.bitwise_and(dst, v_dst)

    return dst

色抽出する処理を関数にまとめてみました.
この関数の戻り値と引数は以下のようになります.黒を除外して色相で抜きたい色を指定するイメージで処理を行います.
出力画像 extract_color( 入力画像, 色相のしきい値(下), 色相のしきい値(上), 彩度のしきい値, 明度のしきい値 )
関数の内部の処理を説明します.
入力画像はRGBカラーモデルであることを想定し,HSV色空間に変換します.
その後,HSVの各チャンネルを別々の画像にわけます.
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
赤色を抽出する場合は,色相が360°をまたぐ可能性があるため,ここで処理を分けます.
色相のしきい値(下)がしきい値(上)より大きいというのは,赤のように350°から10°までというような場合を想定しています.
360°を境界として2回しきい値処理を行った後に各画像を合わせることで抽出します.
まず,以下のようなcv2.threshold関数を使って,しきい値処理を行います.
cv2.threshold(画像, しきい値, 最大値, しきい値処理のタイプ)
しきい値処理のタイプは以下のものを使用します.

cv2.THRESH_BINARY: しきい値より大きい値は最大値,それ以外は0
cv2.THRESH_BINARY_INV: しきい値より大きい値は0,それ以外は最大値

その後,各画像のORを取ることで,2枚の画像を合わせます.
    if h_th_low > h_th_up:
        ret, h_dst_1 = cv2.threshold(h, h_th_low, 255, cv2.THRESH_BINARY) 
        ret, h_dst_2 = cv2.threshold(h, h_th_up,  255, cv2.THRESH_BINARY_INV)
        
        dst = cv2.bitwise_or(h_dst_1, h_dst_2)
次に,360°をまたがない場合を考えます.
ここでは,しきい値処理に以下のものを使用します.

cv2.THRESH_TOZERO: しきい値よりより大きい値はそのまま,それ以外は0
cv2.THRESH_TOZERO_INV: しきい値よりより大きい値は0,それ以外はそのまま

まず,しきい値(下)の値を0にし,その後,しきい値(上)より大きい値を0にすることで特定の範囲の値を抽出できます.
    else:
        ret, dst = cv2.threshold(h,   h_th_low, 255, cv2.THRESH_TOZERO) 
        ret, dst = cv2.threshold(dst, h_th_up,  255, cv2.THRESH_TOZERO_INV)

        ret, dst = cv2.threshold(dst, 0, 255, cv2.THRESH_BINARY)
色相については,ここまでで処理できたので,残りの明度と彩度についても処理を行います.
ここでは,黒に近い色を排除するだけでよいので,下限値のみのしきい値処理を行います.
    ret, s_dst = cv2.threshold(s, s_th, 255, cv2.THRESH_BINARY)
    ret, v_dst = cv2.threshold(v, v_th, 255, cv2.THRESH_BINARY)
そして最後に,各画像のANDをとり,各しきい値を満たす画素を抽出します.
    dst = cv2.bitwise_and(dst, s_dst)
    dst = cv2.bitwise_and(dst, v_dst)
これで,任意の色を抽出するextract_color関数が完成しました.

それでは,この関数を使って色抽出を行ってみます.
基本的なWebカメラの扱い使い方は,ここを見てください.
if __name__=="__main__":

    capture = cv2.VideoCapture(0)
    
    if capture.isOpened() is False:

        raise("IO Error")

    cv2.namedWindow("Capture", cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow("Red",     cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow("Yellow",  cv2.WINDOW_AUTOSIZE)

    while True:

        ret, image = capture.read()
        if ret == False:
            continue

        red_image    = extract_color(image, 170, 5,  190, 200)
        yellow_image = extract_color(image, 10,  25, 50,  50)

        cv2.imshow("Capture", image)
        cv2.imshow("Red",     red_image)
        cv2.imshow("Yellow",  yellow_image)
       
        if cv2.waitKey(33) >= 0:
            cv2.imwrite("image.png", image)
            cv2.imwrite("red_image.png", red_image)
            cv2.imwrite("yellow_image.png", yellow_image)
            break

    cv2.destroyAllWindows()
このスクリプトの実行結果は以下のようになります.
まずは,入力画像です.
image
次に,赤色の抽出結果です.
red_image
最後に,黄色の抽出結果です.
yellow_image

この例では,赤色と黄色をそれぞれ抽出して画像を表示しています.
各画像を見ると,それぞれの色で抽出出来ていることがわかります.
基本的な処理は既に説明していますが,OpenCVではHSVの各チャンネルは以下のような値域となっていることに注意してください.

H(色相):0~180
S(彩度):0~255
V(明度):0~255

以上でHSV色空間で色抽出をする方法の説明を終わります.  

Python版OpenCV関連の記事:
Python版OpenCVでWebカメラの画像を取得する
Python版OpenCVで色抽出を行う

参考文献:
「Miscellaneous Image Transformations」『OpenCV 2.4.9.0 documentation』<http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html> (2015/02/20アクセス)
「Basic Operations on Images」『OpenCV 3.0.0-dev documentation』<http://docs.opencv.org/trunk/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.html> (2015/02/20アクセス) 

コメント

このブログの人気の投稿

C++11のためにGCCの最新版をインストールする

分解:Logicool M570

MOCO'Sキッチンのフォントに似せるβ版