謎's キッチン

謎のひとりごと。Amazon欲しい物リストはこちら: https://www.amazon.co.jp/hz/wishlist/ls/CCPOV7C6JTD2

デストラクタ/スマートポインタ

C言語でデストラクタ及びスマートポインタを実装した人が居るらしい。何というタイミング。GCC拡張のcleanup attributeを使っているので、使い道は少なそう。それと、メモリをスタックからじゃなくてヒープから取得してるのが気になる。

[C] Implementing smart pointers for the C programming language
http://snaipe.me/c/c-smart-pointers/
https://github.com/Snaipe/c-smart-pointers

右辺値参照とムーブセマンティクス

C++11は良く分からんので、C言語で。参照でもないけど、実装は似たようなもん。デコンストラクタ問題やオーバーロード演算子オーバーライドが無いので別物だけど、これはこれで使い道ある気がする。

moveについては、safe_freeのような趣きがあって良ろしいかな。unique_ptrのようなものを作るのにはcoccinelleのようなソフトの支援を借りなければならないけど、coccinelleならコンテキストに依存した複雑な制約を課すことが容易なので、それはそれで色々出来そう。

#include <stddef.h>
#include <stdio.h>
#include <alloca.h> 

/*
static inline void *_move(void **p){
  void *q = *p;
  *p = NULL;
  return q;
}
#define move(p) _move((void **)&p)

#define to_rvref(v) ((*(volatile typeof(v)*)alloca(sizeof(v))) = v,alloca(0)) // buggy
*/

// GCC拡張
#define move(p) ({typeof(p) __q = p; p = NULL; __q;})
#define to_rvref(v) ({typeof(v)* __p = alloca(sizeof(v)); *__p = v; __p;})

int *test(){
  int *u = NULL, *v = to_rvref(12345678);
  printf("%d\n", *v);
  u = move(v);
  printf("%d\n", *u);
  printf("%p\n", v);
  return u;
}

__attribute__((optimize("O0")))
void breakstack(){
   int **p = alloca(sizeof(int*)*3);
   *p++ = NULL;
   *p++ = NULL;
   *p++ = NULL;
}

int main(){
  int *p = test();
  breakstack();
  printf("%d\n", *p); // broken
}

モスキートノイズ

色々弄って、いい感じにはなったが、どうにも線が欠ける。
ソースがjpegなので、モスキートノイズが原因のように見える。

先にMosquitoNRの移植を行うべきだったか。
いや、Adaptive Bilateral Filterで十分な気もする。問題はOpenCV 3.0でadaptiveBilateralFilterがドロップされちゃってることだけども。

IDEとPython (タイプヒンティング、その他)

Pythonでは、タイプヒンティングの構文が標準化されておらず、実装によって構文がバラバラ。
import周りの規則もややこしいことこの上ない。ということで、コード補完のための定義ファイルの生成周りが理解しきれてない。


bpy.types.bpy_prop_collectionのためにGeneric型が欲しいのだが、PyDevはGeneric型に対応していないらしい。なので、現時点で自動補完するならPyDevよりもPyCharmの方が良いはず。

Does PyDev's type hinting support generic types?
http://stackoverflow.com/questions/23876497/does-pydevs-type-hinting-support-generic-types

PyCharmがジェネリックに対応しているとはいっても、クラスのジェネリック型で__init__が必須だったり、プロパティ(ゲッター)の型の処理が怪しかったりと罠多め。
タイプヒンティングの標準化が進んでいるらしく、それはPyCharmの構文とかなり異なるので、標準化されるまで待った方が懸命かもなぁ。

K-meansじゃダメだ

x軸はグレースケールの色と最頻値との差の絶対値、y軸は画像の外周を中心に円にした時の中心からの距離。下図の右下を切り離したいので、別のクラスタリング手法を使う必要がありそう。


しかし、OpenCVにはk-meansしか用意されていないので、sklearnを入れてみた。色々なクラスタリング法が使えて面白い。ただ、遅いからサンプル数を間引かないといけないけども。

  • スペクトラルクラスタリングはメモリが大量に必要とのことで断念。
  • Ward法はk-meansと似た結果でダメだった。
  • DBSCANは良さげに見えるけど、今回のケースでは不可能。
  • 凝集クラスタリングで良い結果を得られた。


しかし、別のケースでは上手く行ってない。

クラスタ数増やしたら一応上手く行ったけど、安定した方法では無さげ。さてどうするかな。外れ値検出とか? アウトラインフラグメント化とか?

画像の外周を中心に円にする

中心からの距離をk-meansの要素に使えないかなと思って、作ってみた。

import sys
import cv2
import numpy as np
import math

def main():
    if len(sys.argv) != 3:
        print "./circle_transform.py <in_file> <out_file>"
        quit()

    filename = sys.argv[1]
    outfile = sys.argv[2]

    image = cv2.imread(filename, cv2.IMREAD_COLOR)

    if image is None:
        print "input file is not found"
        quit()

    circle = np.zeros([image.shape[0], image.shape[1], 2], dtype=np.float)
    center = [image.shape[0]/2.0, image.shape[1]/2.0]

    for i in range(0, image.shape[0]):
        for j in range(0, image.shape[1]):
            pos = [i-center[0], j-center[1]]
            if pos[0] == 0: continue
#            n = pos[1]/pos[0] # y = nx, x = y/n
#            if n == 0: continue
            circle[i,j,0] = 1.0 - max(abs(pos[0]/center[0]),  abs(pos[1]/center[1]))
#            circle[i,j,0] = 1.0 - math.sqrt(pos[0]**2 + pos[1]**2) / math.sqrt(min(center[0]**2 + (n*center[0])**2, center[1]**2 + (center[1]/n)**2))
            circle[i,j,1] = math.atan2(pos[1], pos[0])

    img_out_size = max(image.shape[0], image.shape[1]) / 2.0
    img_out = np.zeros([img_out_size, img_out_size, image.shape[2]], dtype=np.uint8)

    out_half = [img_out.shape[0]/2.0, img_out.shape[1]/2.0]
    for i in range(0, image.shape[0]):
        for j in range(0, image.shape[1]):
            dist = circle[i,j,0]
            rad = circle[i,j,1]
            idx_x = (math.cos(rad)*dist*out_half[0] + out_half[0])%img_out.shape[0]
            idx_y = (math.sin(rad)*dist*out_half[1] + out_half[1])%img_out.shape[1]
            img_out[idx_x, idx_y] = image[i, j]

    cv2.imwrite(outfile, img_out)

main()


最適化した。

3.0.0-beta

OpenCV 3.0ではPythonからT-API経由でOpenCLが使えるらしいと聞いて、さっそくパッケージ化して入れてみた。
パッケージは下記。手抜きなので、2.xのパッケージを全部削除してから入れないとダメなど、色々問題あるけれども自己責任で。
http://www4.pf-x.net/nazodane/opencv_3.0.0-beta-1_amd64.deb


3.0ではレガシーなAPIが廃止されたとのことだが、移行ドキュメントが見当たらないし、Google検索では旧APIが引っかかりまくってて残念。取りあえず、引っかかったものだけ挙げてみる。

  • cv2.CV_LOAD_IMAGE_COLOR → cv2.IMREAD_COLOR
  • cv2.cv.CV_TERMCRIT_ITER → cv2.TERM_CRITERIA_MAX_ITER
  • cv2.cv.CV_TERMCRIT_EPS → cv2.TERM_CRITERIA_EPS
  • 旧: cv2.kmeans(data, K, criteria, attempts, flags[, bestLabels[, centers]]) → retval, bestLabels, centers
  • 新: cv2.kmeans(data, K, bestLabels, criteria, attempts, flags[, centers]) → retval, bestLabels, centers
  • 旧: cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) → contours, hierarchy
  • 新: cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) → image, contours, hierarchy


動かしたところ、sudo nvidia-settings -q GPUCurrentClockFreqs を見る限り、ちゃんとOpenCLを使ってるようだ。