2008-01-05[n年前へ]
2017-07-02[n年前へ]
■USB顕微鏡で「簡易立体顕微鏡」を作ってみる
今日は、USB顕微鏡を使って「立体顕微鏡」を作ってみました。照明周りとソフト側をいじり、下記のような撮影をして、Shape From Specular 手法で法線積分から形状生成をすることで、カラー立体画像を撮影可能なUSB立体顕微鏡へ変身させてみる!という具合です。つまり、USB顕微鏡を「照明光の向きと各画素に対する撮影方向から、法線方向を推定し、その法線積分による形状を生成する」USB 3次元形状撮影顕微鏡に変身させてみた…という具合です(撮影のようすは、下に貼り付けた動画を見るとわかりやすいかもしれません)。
下に貼り付けた、添付画像は「五千円札の樋口一葉」の目を中心にした「1ミリメートル角くらい」ぐらい部分を撮影してみたものです。五千円札の樋口一葉の眼を描く、インクの超盛り上がり具合を確認することができます。
といっても、お札は偽造防止のために、触感でも本物・偽物をすぐに判別できるように、超盛り盛りでインクを盛り上げてあります。だから、これくらいの撮影ができなければ、…実際のところ「立体顕微鏡」なんて名乗る資格は無いのです。
今や高倍率のUSB顕微鏡も1000円くらいで買うことができる時代。そして、「あったらいいな」と思うことを実現する処理アルゴリズムも、コンピュータで簡単に走らせることができる今日この頃。
それはつまり、千円あれば「あんなことやこんなこと」…色んなことができるというのが2017年の夏なのかも、と思ったりします。
2018-04-28[n年前へ]
■草間彌生デザインの「水玉模様のモジモジ君ウェア」で人体の表面形状を推定してみよう!
数ヶ月前に買ったつもりのZOZOスーツ、服に取り付けられたセンサ群とスマホの間でさまざまなデータが交換され、自分の体を知ることができるという「面白さ」に惹かれて…はや数ヶ月、「大幅な性能向上」したものが届くという連絡内容を見ると、、そこには「コレジャナイ感が、超大盛りラーメン店のようにテンコ盛りされた、草間彌生デザインの「水玉模様のモジモジ君ウェア」でした。マーカー付けた衣服を使って(スマホによる)画像計測による採寸を行うデザインに変わっていた…というわけです。
ネットには、新バージョンのZOZOスーツ試着写真もtwitterにはアップロードされ始めています。そこで、そんなマーカ模様が付けられた服を着用した画像からの人体形状推定をしてみることにしました。「ネットにアップされた画像から」というわけで、多視点撮影からの3次元推定を行うZOZOスーツ正式バージョンとは違い、一枚画像からの体表面形状の推定です。
書いてみたのは、下に貼り付けたような、十数行ばかりのPython/Jupyterコードです。OpenCV でテクスチャ検出をして、その(円形マーカーの)大きさや形状の歪みを使って、模様部分の体の表面形状情報を推定する…というわけです。Pythonコードを実行した結果は、たとえば下の4 図のようになります。向かって左から、元画像・高さ(凹凸)画像・向き(180度の反対側を区別できない)画像・法線画像です。この処理例は、水玉模様の水着画像で処理を行ったものですが、新型ZOZOスーツ画像でも同様のことが行えます。
この画像を見れば、水着の模様を介して胸やお腹の3次元形状が見えてくることがわかります。全身に模様が付けられたZOZOスーツを着用した自撮り写真がアップされたら…色んな体形状を可視化できそうです。
import numpy as np import cv2 from matplotlib import pyplot as plt from math import sin, cos img = cv2.imread('zozo_polka202.jpg',2) cimg = cv2.cvtColor( cv2.imread('zozo_polka202.jpg'), cv2.COLOR_RGB2BGR) img = cv2.adaptiveThreshold(img, 128, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 15, 5) img, contours, hierarchy = cv2.findContours( img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) if len(contours) > 0: for i, contour in enumerate(contours): if (contour.shape)[0]>4: ellipse = cv2.fitEllipse(contour) aMax = max(ellipse[1][0],ellipse[1][1]) aDiff = abs(ellipse[1][0]-ellipse[1][1]) if aMax < 20 and aMax > 11 and aDiff < 12: xc = sin(ellipse[2]*np.pi/180)*255 yc = cos(ellipse[2]*np.pi/180)*255 cx=int(ellipse[0][0]) cy=int(ellipse[0][1]) cv2.ellipse(cimg,ellipse, (xc,yc,255-xc),-1) #cv2.circle(cimg, (cx, cy), int((aMax-11)*2.0), (xc,yc,255-xc), -1, -1) #cv2.ellipse(cimg,ellipse,(int((aMax-11)*50.0), int((aMax-11)*50.0),int((aMax-11)*50.0)),-1) #cv2.ellipse(cimg,ellipse,(int((aMax-11)*50.0), yc+xc,int((aMax-11)*50.0)),-1) plt.imshow(np.array(cimg))