俺言語。

自分にしか理解できない言語で書かれた備忘録

【Python】numpy2次元配列でキーを使ったソートの方法

エクセルの並び替えの様に優先するキー(軸)を指定した並び替えが少しめんどくさい。
なぜそれ用の関数orオプションがないのだろうか…。

方法としては

  1. キーにする軸のみargsortでソート後のインデックスを取り出す
  2. そのインデックスを使ってソートする前の配列から新しい配列を作る
  3. np.c_で配列を結合


具体的な方法は

import numpy as np

# 100x2の配列を作成
a = np.random.rand(100,2) 

# キー軸をソートした後のインデックスを取り出す
ind = np.argsort(a[:,0])

# ソート後のインデックスで元の配列を並び替え
new_a0 = a[ind, 0]
new_a1 = a[ind, 1]

# 配列を結合
new_aa = np.c_[new_a0, new_a1]

実際は全て一行にまとめて

new_aa = np.r_[a[np.argsort(a[:, 0]), 0], a[np.argsort(a[:, 0]), 1]]

って書いたりする。

【Python】GetWindowTextで取得できない文字列を取得する方法(win32api SendMessage WM_GETTEXT)

GetWindowTextで文字列が取得できない場合(他プロセスのコントロール文字列は取得できないらしい、意味不明)は

指定のハンドルにメッセージを投げて文字列を取得する。

投げるメッセージの定数はwinuser32.h内に記載されている。

ハンドルはspy++等で調べることが可能,16進数の整数。

SendMessageは末尾に"A"(ANSI版)と"W"(unicode版)どちらかが選択できるが

日本語で帰ってくる可能性があるはずなので"W"にしてみている。今のところ問題はなし。

import ctypes

def get_control_text():
     # ハンドル
     hwnd = 0x0001096C

     # 定数はwinuser.hに定義されている
     msg_gettextlength = 0x000E
     msg_gettext = 0x000D

     # 受け取るテキストの文字長さを取得(wParam,lParamは0にすること) 終端文字列は含まず
     len_str = ctypes.windll.user32.SendMessageW(hwnd, msg_gettextlength, 0, 0 )

     # 文字列バッファを定義
     buff = ctypes.create_unicode_buffer(len_str + 1)

     # 文字列を取得 第3引数にwParamに文字数,第4引数にlParamに文字列バッファ
     ctypes.windll.user32.SendMessageW(hwnd, msg_gettext, len_str +1, buff )

【Python】ウィンドウのタイトル文字列を取得する方法(win32api user32 GetWindowText)

win32apiのGetWindowTextを使ってウィンドウの文字列を取得する方法 <流れ>

1.EnumWindowsでトップレベル(アクティブという意味ではない)のウィンドウハンドルを取得
 EnumWindowsは引数にコールバック関数が必要なのでコールバック関数を定義


2.GetWindowTextLengthでタイトル長を取得(タイトル長は終端文字を含まない点に注意)


3.タイトル名を格納するバッファをctypes.create_unicode_bufferで用意 バッファ長は終端文字を含むため
 GetWindowTextLength +1にすること


4.GetWindowTextでタイトルを取得
 引数は(ウィンドハンドル,文字列用バッファのポインタ,文字列長)

import ctypes

def get_window_title():

    """
    ctypes.WINFUNCTYPE(戻り値の型, コールバック関数が想定する引数の型)
        : windowsのコールバック関数を定義 定義するだけなので引数は具体的なインスタンスではなく型を指定するのがミソ?

    user32.EnumWindows: トップレベルウィンドウのハンドルを順番にコールバック関数へ送る

    user32.IsWindowVisible(hwnd): 可視化されたウィンドウであればTrueを返す

    user32.GetWindowTextLengthW(hwnd):ウィンドウハンドルのテキスト長を返す

    ctypes.create_unicode_buffer(長さ): 変更可能な文字列?を作成 型は文字列配列になる 意味的には w_char*10と同じ,違いが良くわからん

    user32.GetWindowTextW(hwnd, 文字列格納用バッファ, 文字列長さ)

    ctypes.POINTER():引数型のポインタを作成
    ctypes.pointer():引数のポインタを返す
    """


    # コールバック関数を定義(定義のみで実行ではない) コールバック関数はctypes.WINFUNCTYPEで作成可能
    EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
    # ??
    EnumWindows = ctypes.windll.user32.EnumWindows
    # タイトル格納用変数
    title = []

    def foreach_window(hwnd, lparam):
        if ctypes.windll.user32.IsWindowVisible(hwnd):
            length = ctypes.windll.user32.GetWindowTextLengthW(hwnd)
            buff = ctypes.create_unicode_buffer(length +1)
            ctypes.windll.user32.GetWindowTextW(hwnd, buff, length + 1)
            title.append(buff.value)

            return True

    EnumWindows(EnumWindowsProc(foreach_window), 0)

    print title

↓参考にしたサイト
sjohannes.wordpress.com

【Python】str.isdigitsは小数を判定できない罠

文字列が数値かどうか判定するstr.isdigits

"."が含まれていると数値として判定してくれない。

str.isdigits("123") 
>> True

str.isdigits("12.3")
>> False

回避方法としては簡単なものはreplaceメソッドで"."を""に置換してしまうこと。

str.isdigits("12.3".replace(".",""))
>> True

但しこれは厳密にいうと数字でない".123"や"..123"もTrueが返ってきてしまうので要注意。

この場合は正規表現を使ってやる必要があるみたい。

↓参考になったサイト
d.hatena.ne.jp

【Python】openCVのcv2.imshow()でエラー error: (-215) size.width>0 && size.height>0 in function cv::imshow

動画を読み込んで表示するプログラムでエラーが発生。

import cv2

src_m = cv2.VideoCapture("ファイル名")

r, f = src_m.read() #←1フレーム読み込み
cv2.imshow('title', f) #←フレーム表示

aviファイルはエラーが出ずに表示できるものとできない物があった。
エラーが出なかったものも画像が斜めに変形して表示されおかしい状態。
mp4, tsは読み込み出来ずだった。

エラーメッセージは

error: ..\..\..\..\opencv\modules\highgui\src\window.cpp:261: error: (-215) size.width>0 && size.height>0 in function cv::imshow

原因は"import cv2"でインポートされるモジュール cv2.pyd が

何故かc:\Python\DLLs 内に単独であって

本来インポートされるべき

C:\Python27\Lib\site-packages 内の cv2.pyd が読み込まれていなかった。

たぶんインポートの順番かPYTHONPATHの記述の順番のせいか?


これはcv2をインストールし直した時のバージョンと

インポートして cv2.__version__ で確認したバージョンが一致しなかったことから判明。


このエラーは cv2.pyd と同じディレクトリにopencv_ffmpegという恐らく

デコード担当のファイルがない時に出るらしく今回はまさにそれだったと思われる。


opencv_ffmpegが同じディレクトリに必要というのは下記にあった。
stackoverflow.com

【Python】マウス左クリックした位置の画面座標を取得しコンソールに出力

win32apiの
user32.GetCursorPosとuser32.GetAsyncKeyStateを組み合わせて
左クリックした位置の座標を取得し,コンソールに出力するプログラム

下記は2回クリックして1回目が左上,2回目を右下とする矩形の座標を呼び出し元に返すプログラム

# -*- coding: utf-8 -*-

import ctypes
import time

def get_rectcordinate():

    # 構造体を定義
    class _pointer(ctypes.Structure):
        _fields_ = [
            ('x', ctypes.c_long),
            ('y', ctypes.c_long),
        ]

    # 構造体を初期化
    point_topleft = _pointer()
    point_bottomright = _pointer()

    ## 監視領域をクリックして取得------------------------------------------------------------------
    vk_leftbutton = 0x01 #マウス左ボタン Virtual Keyboad
    vk_esc = 0x1B # ESC Virtual Keyboad

    # 監視領域の左上をクリック
    print u"Click Leftbutton for Watch Area of Top-Left"

    while 1:
        if ctypes.windll.user32.GetAsyncKeyState(vk_leftbutton) == 0x8000: #0b1000 0000 0000 0000
            # 構造体のポインタを引数で渡す(参照渡し)
            ctypes.windll.user32.GetCursorPos(ctypes.byref(point_topleft))

            print "X:" + str(point_topleft.x) + ", Y:" + str(point_topleft.y) + "\n\r"
            break
        elif ctypes.windll.user32.GetAsyncKeyState(vk_esc) == 0x8000:

            print "Canceled"
            break

    # 監視領域の右下をクリック
    time.sleep(0.2)
    print u"Click Leftbutton for Watch Area of Bottom-right"

    while 1:
        if ctypes.windll.user32.GetAsyncKeyState(vk_leftbutton) == 0x8000: #0b1000 0000 0000 0000
            # 構造体のポインタを引数で渡す(参照渡し)
            ctypes.windll.user32.GetCursorPos(ctypes.byref(point_bottomright))

            print "X:" + str(point_bottomright.x) + ", Y:" + str(point_bottomright.y) + "\n\r"
            break
        elif ctypes.windll.user32.GetAsyncKeyState(vk_esc) == 0x8000:

            print "Canceled"
            break

    return ((point_topleft.x, point_topleft.y, point_bottomright.x, point_bottomright.y))

【Python】win32apiを使ってあるキーが押されたか検知する

関数名は

user32.GetAsyncKeyState(vk_leftbutton)

キーボードだけでなくマウスクリックも検知できる。

戻り値が0x8000,
2進数だと16bitで 0b1000 0000 0000 0000
が返ってこれば押されてると判定。
押されていない時の戻り値は確か0だったはず。

引数にはバーチャルキーコード(定数)を与える。

例えばマウス左クリックとESCは

vk_leftbutton = 0x01 #マウス左ボタン Virtual Keyboad
vk_esc = 0x1B # ESC Virtual Keyboad