Ubuntu 16.04 lts + CUDA9.0 + cuDNN 7.1.3 Tensorflow1.6 コンパイルまで

Ubuntu14.04 LTS を dist upgrade で、16.04 にしたので、CUDA と cuDNN を入れ直しすことにしました。

NVIDIA Driver を入れ直す

Before installing the CUDA Toolkit on Linux, please ensure that you have the latest NVIDIA driver R390 installed. The latest NVIDIA R390 driver is available at: www.nvidia.com/drivers

を発見。

現在のバージョンを確認。

$ nvidia-smi 
Tue May  1 21:25:53 2018       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.111                Driver Version: 384.111                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  Off  | 00000000:06:00.0  On |                  N/A |
|  0%   39C    P8     9W / 120W |     52MiB /  6071MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1135      G   /usr/lib/xorg/Xorg                            50MiB |
+-----------------------------------------------------------------------------+

とのことなので、Driver を先に入れよう。

$ dpkg -l | grep nvidia
$ dpkg -l | grep cuda

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update

$ sudo apt-get install nvidia-390

$ sudo reboot

$ nvidia-smi 
Tue May  1 22:00:43 2018       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.48                 Driver Version: 390.48                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  Off  | 00000000:06:00.0  On |                  N/A |
|  0%   43C    P0    29W / 120W |     61MiB /  6077MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1049      G   /usr/lib/xorg/Xorg                            59MiB |
+-----------------------------------------------------------------------------+

CUDA インストール

sudo dpkg -i cuda-repo-ubuntu1604_9.1.85-1_amd64.deb sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub sudo apt-get update sudo apt-get install cuda

なお、Tensorflow が、 CUDA9.0 を求めてきたので、

$ sudo apt-get install cuda-9-0

となりました。

邪魔していたのを対処

$ sudo aptitude install cuda

path を通す

cuDNN インストール

tensorflow インストール

sudo pip install tensorflow

で、1.8 かなにかが入ったんですが、tensorflow Illegal instruction core dump でてしまって、困りました。

回避策として、

$ sudo pip install tensorflow-gpu==1.5

となりました。

pipでバイナリをインストールした場合、1.6以降ではAVX がONになっていて、CPU が AVX に対応していないと、エラーに成るようです。

Note: Starting from 1.6 release, our prebuilt binaries will use AVX instructions. Older CPUs may not be able to execute these binaries.

回避策としては、1.5を使用するか、pip ではなく、自分で AVX OFF でコンパイルすることらしいです。

Tensorflow を、コンパイルする

Installing TensorFlow from Sources  |  TensorFlow

git で取得

$ git clone https://github.com/tensorflow/tensorflow
$ cd tensorflow
$ git checkout r1.6

$ ./configure

build

$ bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.8.0-py2-none-any.whl

Tensorflow で SSD

動作環境

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="14.04.5 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.5 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2016 NVIDIA Corporation
Built on Tue_Jan_10_13:22:03_CST_2017
Cuda compilation tools, release 8.0, V8.0.61

$ ls /usr/local/cuda/lib64/libcudnn.so.*
/usr/local/cuda/lib64/libcudnn.so.5  /usr/local/cuda/lib64/libcudnn.so.5.1.10


$ pip list | grep tensorflow
tensorflow-gpu                1.4.1             
tensorflow-tensorboard        0.4.0

$ python
Python 3.4.3 (default, Nov 28 2017, 16:41:13) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.

SSD の取得と、設定?

$ git clone https://github.com/balancap/SSD-Tensorflow.git

$ cd SSD-Tensorflow
$ cd checkpoints
$ unzip ssd_300_vgg.ckpt.zip

サンプルコードを改変して、動かす

$ cd ../notebooks/

$ jupyter nbconvert --to python ssd_notebook.ipynb

matplotlib の設定

$ cat ~/.config/matplotlib/matplotlibrc 
font.family : IPAexGothic
backend      : tkagg

サンプルコードを改変

せっかくなので、すべての画像を処理することと、ラベルを設定しました。

./datasets/pascalvoc_common.py

の中身を、使用しやすいように書き換えてます。

SSDによる物体検出を試してみた - TadaoYamaokaの日記

こちら様のデータを使用しています。

ssd_notebook.py
# coding: utf-8

import os
import math
import random

import numpy as np
import tensorflow as tf
import cv2

slim = tf.contrib.slim

#get_ipython().magic('matplotlib inline')
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import sys
sys.path.append('../')

from nets import ssd_vgg_300, ssd_common, np_methods
from preprocessing import ssd_vgg_preprocessing
from notebooks import visualization

# TensorFlow session: grow memory when needed. TF, DO NOT USE ALL MY GPU MEMORY!!!
gpu_options = tf.GPUOptions(allow_growth=True)
config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options)
isess = tf.InteractiveSession(config=config)


# ## SSD 300 Model
# 
# The SSD 300 network takes 300x300 image inputs. In order to feed any image, the latter is resize to this input shape (i.e.`Resize.WARP_RESIZE`). Note that even though it may change the ratio width / height, the SSD model performs well on resized images (and it is the default behaviour in the original Caffe implementation).
# 
# SSD anchors correspond to the default bounding boxes encoded in the network. The SSD net output provides offset on the coordinates and dimensions of these anchors.

# Input placeholder.
net_shape = (300, 300)
data_format = 'NHWC'
img_input = tf.placeholder(tf.uint8, shape=(None, None, 3))
# Evaluation pre-processing: resize to SSD net shape.
image_pre, labels_pre, bboxes_pre, bbox_img = ssd_vgg_preprocessing.preprocess_for_eval( img_input, None, None, net_shape, data_format, resize=ssd_vgg_preprocessing.Resize.WARP_RESIZE)
image_4d = tf.expand_dims(image_pre, 0)

# Define the SSD model.
reuse = True if 'ssd_net' in locals() else None
ssd_net = ssd_vgg_300.SSDNet()
with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):
        predictions, localisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=reuse)

# Restore SSD model.
ckpt_filename = '../checkpoints/ssd_300_vgg.ckpt'
# ckpt_filename = '../checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt'
isess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(isess, ckpt_filename)

# SSD default anchor boxes.
ssd_anchors = ssd_net.anchors(net_shape)


# ## Post-processing pipeline
# 
# The SSD outputs need to be post-processed to provide proper detections. Namely, we follow these common steps:
# 
# * Select boxes above a classification threshold;
# * Clip boxes to the image shape;
# * Apply the Non-Maximum-Selection algorithm: fuse together boxes whose Jaccard score > threshold;
# * If necessary, resize bounding boxes to original image shape.

# Main image processing routine.
def process_image(img, select_threshold=0.5, nms_threshold=.45, net_shape=(300, 300)):
        # Run SSD network.
        rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, predictions, localisations, bbox_img], feed_dict={img_input: img})

        # Get classes and bboxes from the net outputs.
        rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select( rpredictions, rlocalisations, ssd_anchors, select_threshold=select_threshold, img_shape=net_shape, num_classes=21, decode=True)

        rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)
        rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)
        rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)
        # Resize bboxes to original image shape. Note: useless for Resize.WARP!
        rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)
        return rclasses, rscores, rbboxes


# Test on some demo image and visualize output.
path = '../demo/'
image_names = sorted(os.listdir(path))

for i in range(12):
        img = mpimg.imread(path + image_names[i])
        rclasses, rscores, rbboxes =  process_image(img)
visualization.py
# Copyright 2017 Paul Balanca. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
import sys
import cv2
import random

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import matplotlib.cm as mpcm

VOC_LABELS = {
    0: 'none',
    1: 'aeroplane',
    2: 'bicycle',
    3: 'bird',
    4: 'boat',
    5: 'bottle',
    6: 'bus',
    7: 'car',
    8: 'cat',
    9: 'chair',
    10: 'cow',
    11: 'diningtable',
    12: 'dog',
    13: 'horse',
    14: 'motorbike',
    15: 'person',
    16: 'pottedplant',
    17: 'sheep',
    18: 'sofa',
    19: 'train',
    20: 'tvmonitor',
}

# =========================================================================== #
# Some colormaps.
# =========================================================================== #
def colors_subselect(colors, num_classes=21):
        dt = len(colors) // num_classes
        sub_colors = []
        for i in range(num_classes):
                color = colors[i*dt]
                if isinstance(color[0], float):
                        sub_colors.append([int(c * 255) for c in color])
                else:
                        sub_colors.append([c for c in color])
        return sub_colors

colors_plasma = colors_subselect(mpcm.plasma.colors, num_classes=21)
colors_tableau = [(255, 255, 255), (31, 119, 180), (174, 199, 232), (255, 127, 14), (255, 187, 120),
                                (44, 160, 44), (152, 223, 138), (214, 39, 40), (255, 152, 150),
                                (148, 103, 189), (197, 176, 213), (140, 86, 75), (196, 156, 148),
                                (227, 119, 194), (247, 182, 210), (127, 127, 127), (199, 199, 199),
                                (188, 189, 34), (219, 219, 141), (23, 190, 207), (158, 218, 229)]


# =========================================================================== #
# OpenCV drawing.
# =========================================================================== #
def draw_lines(img, lines, color=[255, 0, 0], thickness=2):
        """Draw a collection of lines on an image.
        """
        for line in lines:
                for x1, y1, x2, y2 in line:
                        cv2.line(img, (x1, y1), (x2, y2), color, thickness)


def draw_rectangle(img, p1, p2, color=[255, 0, 0], thickness=2):
        cv2.rectangle(img, p1[::-1], p2[::-1], color, thickness)


def draw_bbox(img, bbox, shape, label, color=[255, 0, 0], thickness=2):
        p1 = (int(bbox[0] * shape[0]), int(bbox[1] * shape[1]))
        p2 = (int(bbox[2] * shape[0]), int(bbox[3] * shape[1]))
        cv2.rectangle(img, p1[::-1], p2[::-1], color, thickness)
        p1 = (p1[0]+15, p1[1])
        cv2.putText(img, str(label), p1[::-1], cv2.FONT_HERSHEY_DUPLEX, 0.5, color, 1)


def bboxes_draw_on_img(img, classes, scores, bboxes, colors, thickness=2):
        shape = img.shape
        for i in range(bboxes.shape[0]):
                bbox = bboxes[i]
                color = colors[classes[i]]
                # Draw bounding box...
                p1 = (int(bbox[0] * shape[0]), int(bbox[1] * shape[1]))
                p2 = (int(bbox[2] * shape[0]), int(bbox[3] * shape[1]))
                cv2.rectangle(img, p1[::-1], p2[::-1], color, thickness)
                # Draw text...
                s = '%s/%.3f' % (classes[i], scores[i])
                p1 = (p1[0]-5, p1[1])
                cv2.putText(img, s, p1[::-1], cv2.FONT_HERSHEY_DUPLEX, 0.4, color, 1)


# =========================================================================== #
# Matplotlib show...
# =========================================================================== #
def plt_bboxes(f_name, img, classes, scores, bboxes, figsize=(10,10), linewidth=1.5):
        """Visualize bounding boxes. Largely inspired by SSD-MXNET!
        """
        fig = plt.figure(figsize=figsize)
        plt.imshow(img)
        height = img.shape[0]
        width = img.shape[1]
        colors = dict()
        for i in range(classes.shape[0]):
                cls_id = int(classes[i])
                if cls_id >= 0:
                        score = scores[i]
                        if cls_id not in colors:
                                colors[cls_id] = (random.random(), random.random(), random.random())
                        ymin = int(bboxes[i, 0] * height)
                        xmin = int(bboxes[i, 1] * width)
                        ymax = int(bboxes[i, 2] * height)
                        xmax = int(bboxes[i, 3] * width)
                        rect = plt.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin, fill=False, edgecolor=colors[cls_id], linewidth=linewidth)
                        plt.gca().add_patch(rect)
                        class_name = str(cls_id)
                        class_name = VOC_LABELS[cls_id]

                        plt.gca().text(xmin, ymin - 2, '{:s} | {:.3f}'.format(class_name, score), bbox=dict(facecolor=colors[cls_id], alpha=0.5), fontsize=12, color='white')
        plt.savefig( './results/'+f_name + '.png' )
        plt.show()

結果

f:id:pongsuke:20180420141915p:plainf:id:pongsuke:20180420141920p:plainf:id:pongsuke:20180420141926p:plainf:id:pongsuke:20180420141931p:plainf:id:pongsuke:20180420141935p:plainf:id:pongsuke:20180420141939p:plainf:id:pongsuke:20180420141943p:plainf:id:pongsuke:20180420141947p:plainf:id:pongsuke:20180420141952p:plainf:id:pongsuke:20180420141958p:plainf:id:pongsuke:20180420142003p:plainf:id:pongsuke:20180420142008p:plain

Opencv Aruco で Pose estimation する その2 estimatePoseBoard

今度は estimatePoseBoard を試します。

f:id:pongsuke:20180419112457p:plain

#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
import numpy as np

aruco = cv2.aruco

# WEBカメラ
cap = cv2.VideoCapture(0)

dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters =  aruco.DetectorParameters_create()
# CORNER_REFINE_NONE, no refinement. CORNER_REFINE_SUBPIX, do subpixel refinement. CORNER_REFINE_CONTOUR use contour-Points
parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR

cameraMatrix = np.array( [[1.42068235e+03,0.00000000e+00,9.49208512e+02],
    [0.00000000e+00,1.37416685e+03,5.39622051e+02],
    [0.00000000e+00,0.00000000e+00,1.00000000e+00]] )
distCoeffs = np.array( [1.69926613e-01,-7.40003491e-01,-7.45655262e-03,-1.79442353e-03, 2.46650225e+00] )

cap.set(cv2.CAP_PROP_FPS, 10)
#cap.set(cv2.CAP_PROP_FRAME_WIDTH, 600)
#cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 600)

board = aruco.GridBoard_create(5, 1, 0.04, 0.01, dictionary)

def main():

    ret, frame = cap.read()

    # 変換処理ループ
    while ret == True:
        corners, ids, rejectedImgPoints = aruco.detectMarkers(frame, dictionary, parameters=parameters)
        #print(corners)
        #print(ids)
        #print(rejectedImgPoints)

        aruco.drawDetectedMarkers(frame, corners, ids, (0,255,0))

        for i, corner in enumerate( corners ):
            points = corner[0].astype(np.int32)
            cv2.polylines(frame, [points], True, (0,255,255))
            cv2.putText(frame, str(ids[i][0]), tuple(points[0]), cv2.FONT_HERSHEY_PLAIN, 1,(0,0,0), 1)

        # int valid = estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);
        retval, rvec, tvec = aruco.estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs)

        if retval != 0:
            aruco.drawAxis(frame, cameraMatrix, distCoeffs, rvec, tvec, 0.1)

        cv2.imshow('org', frame)

        # Escキーで終了
        key = cv2.waitKey(50)
        if key == 27: # ESC
            break

        # 次のフレーム読み込み
        ret, frame = cap.read()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass

これでも、やはり、 z axis flipping は発生します。

Opencv Aruco で Pose estimation する その1

Pose estimation ってのは、姿勢推定 なのでしょうか?

estimatePoseSingleMarkers においては、そのマーカーの向きを推定します(多分)。

なお、estimatePoseBoard も有ります。

とにかくやってみましょう。

マーカー画像の用意

f:id:pongsuke:20180419102042j:plain

今回は、マーカーを5つ(0,1,2,3,4)印刷しました。DICT_4X4_50 で作成したものです。

スクリプト

(いくつかのサイト様のコードを参考にさせていただいたのですが、混じってしまって、特定できませんでした。)

#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
import numpy as np

aruco = cv2.aruco

# WEBカメラ
cap = cv2.VideoCapture(0)

dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters =  aruco.DetectorParameters_create()
# CORNER_REFINE_NONE, no refinement. CORNER_REFINE_SUBPIX, do subpixel refinement. CORNER_REFINE_CONTOUR use contour-Points
parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR

cameraMatrix = np.array( [[1.42068235e+03,0.00000000e+00,9.49208512e+02],
    [0.00000000e+00,1.37416685e+03,5.39622051e+02],
    [0.00000000e+00,0.00000000e+00,1.00000000e+00]] )
distCoeffs = np.array( [1.69926613e-01,-7.40003491e-01,-7.45655262e-03,-1.79442353e-03, 2.46650225e+00] )

cap.set(cv2.CAP_PROP_FPS, 10)
#cap.set(cv2.CAP_PROP_FRAME_WIDTH, 600)
#cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 600)

def main():

    ret, frame = cap.read()

    # 変換処理ループ
    while ret == True:
        corners, ids, rejectedImgPoints = aruco.detectMarkers(frame, dictionary, parameters=parameters)
        #print(corners)
        #print(ids)
        #print(rejectedImgPoints)

        aruco.drawDetectedMarkers(frame, corners, ids, (0,255,0))

        for i, corner in enumerate( corners ):
            points = corner[0].astype(np.int32)
            cv2.polylines(frame, [points], True, (0,255,255))
            cv2.putText(frame, str(ids[i][0]), tuple(points[0]), cv2.FONT_HERSHEY_PLAIN, 1,(0,0,0), 1)

        # rvecs, tvecs, _objPoints =   cv.aruco.estimatePoseSingleMarkers( corners, markerLength, cameraMatrix, distCoeffs[, rvecs[, tvecs[, _objPoints]]] )
        rvecs, tvecs, _objPoints = aruco.estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs)
        if ids is not None:
            for i in range( ids.size ):
                #print( 'rvec {}, tvec {}'.format( rvecs[i], tvecs[i] ))
                #print( 'rvecs[{}] {}'.format( i, rvecs[i] ))
                #print( 'tvecs[{}] {}'.format( i, tvecs[i] ))
                aruco.drawAxis(frame, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.1)

        cv2.imshow('org', frame)

        # Escキーで終了
        key = cv2.waitKey(50)
        if key == 27: # ESC
            break

        # 次のフレーム読み込み
        ret, frame = cap.read()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass

f:id:pongsuke:20180419104506p:plain

parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR

で、何かを設定していますが、どの様な差が出るのかわかってません。

z axis flipping 現象

f:id:pongsuke:20180419110109p:plain

z軸が反転するような現象が起こります。(再現して撮影しようとすると、変に大変だったりします。)

これは、バグなのかどうか、スレッドがいろいろ見当たりますが、どうやらバグではなく、そういうもののようです。

f:id:pongsuke:20180419110845p:plain

この画像の、白の面が、どっち向きなのか(天井から下がっているのか、地面に設置されているのか)を、判定できないことと一緒らしいです。

Iterative Pose Estimation Using Coplanar Feature Points

https://pdfs.semanticscholar.org/36bc/490d902061a27b1c598725cd61ad9f1fd4b5.pdf

の画像。

f:id:pongsuke:20180419111218p:plain

じゃあどうする?

今回のように、複数のマーカーが存在し、向きが一緒だとわかっている場合は、マーカーの向きを多数決的に決めてしまえば、ほぼOKとの指摘があります。

opencv チュートリアルチャレンジ カメラキャリブレーション

カメラキャリブレーション — OpenCV-Python Tutorials 1 documentation

Aruco で estimatePoseSingleMarkers を試したいと思ったところ、cameraMatrix と distCoeffs が必要だと判明。

OpenCV: ArUco Marker Detection

estimatePoseSingleMarkers
 Pose estimation for single markers.

cameraMatrix と distCoeffs は、カメラ行列(内部パラメータ) レンズ歪みパラメータ らしい。

Camera Calibration and 3D Reconstruction — OpenCV 3.0.0-dev documentation

Python: cv2.calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs[, rvecs[, tvecs[, flags[, criteria]]]]) → retval, cameraMatrix, distCoeffs, rvecs, tvecs

とにかく取得しましょう。

チェスボードを用意する

https://github.com/opencv/opencv/tree/master/samples/data

こちらから、chessboard.png を取得し、印刷。

曲がらないように、板に貼り付けました。

画像を用意する

キャリブレーションしたいカメラ(今回はWEBカメラ)で、チェスボード用紙を、いろんな角度から撮影します。

(背景にいろいろ写り込んでいたので、写真の掲載は控えます)

ディレクトリ calib を作成し、入れ込んでおきます。

パラメーターを算出する

こちらを参考(ほぼそのまま)にしました。

csharp/calibration.py at master · tanaka0079/csharp · GitHub

myCalib.py

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

import numpy as np
import cv2
from glob import glob

def main():
    square_size = 1.0      # 正方形のサイズ
    pattern_size = (7, 7)  # 交差ポイントの数
    pattern_points = np.zeros( (np.prod(pattern_size), 3), np.float32 ) #チェスボード(X,Y,Z)座標の指定 (Z=0)
    pattern_points[:,:2] = np.indices(pattern_size).T.reshape(-1, 2)
    pattern_points *= square_size
    objpoints = []
    imgpoints = []

    for fn in glob("calib/*.jpg"):
        # 画像の取得
        gray = cv2.imread(fn, 0)
        print("loading..." + fn)

        # チェスボードのコーナーを検出
        ret, corner = cv2.findChessboardCorners(gray, pattern_size)
        # コーナーがあれば
        if ret == True:
            term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1)
            cv2.cornerSubPix(gray, corner, (5,5), (-1,-1), term)
        else:
            print('Chessboard not found!')
            continue
        imgpoints.append(corner.reshape(-1, 2))   #appendメソッド:リストの最後に因数のオブジェクトを追加
        objpoints.append(pattern_points)
        #corner.reshape(-1, 2) : 検出したコーナーの画像内座標値(x, y)

    # 内部パラメータを計算
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
    # 計算結果を表示
    print("RMS = ", ret)
    print("mtx = \n", mtx)
    print("dist = ", dist.ravel())
    # 計算結果を保存
    np.savetxt("ret.csv", np.array([ret]), delimiter =',',fmt="%0.14f")
    np.savetxt("mtx.csv", mtx, delimiter =',',fmt="%0.14f")

if __name__ == '__main__':
    main()

私の結果は、

mtx

1420.68234847996541,0.00000000000000,949.20851179562965
0.00000000000000,1374.16684667116965,539.62205073603297
0.00000000000000,0.00000000000000,1.00000000000000

ret

1.129281781

でした。

Dell alienware aurora r4 Bios update

alienware aurora r4 は、古いけれども、まだまだ使えると思う。

SSDを新品に変えて、Windows10を入れた。

せっかくなので、GeForce GTX 1050ti あたりを入れてみようかな?そもそも対応しているのかな?と、情報を集めていたところ「Biosがアップデートされて入れば動くよ!」という書き込みを発見し、まぁとりあえず Bios update だけでもやってみるかな?と思ったところ、かなり時間がかかったので、備忘録と、日本の何処かの人の助けにはなるかな? と思って記載します。

Bios 設定画面に進めない!

F2 でBios設定画面、F12 で起動オプションをが出る、、、はず。

ところがなんと、今回はここからつまずきました。

刺してあった、ゲーミングキーボードの G510 キーボードでは、F2 を押しまくっても、押し続けても、 Bios設定画面に入れない。

ふと、しまってあったDellのシンプルなUSBキーボードを全面のUSBポートにつなぎ直して挑戦したら、すんなり入れた。

キーボードの違いなのか、USBポートの違いなのかは、不明。

ハードウェア

Dell alienware aurora r4

Bios

現状 A3

目標 A11

ダウンロード

Alienware Aurora R4のサポート | ドライバおよびダウンロード | Dell 日本

アップデートできない!?

A11 アップデートでつまずく

ドキュメントには、windows環境でも、動くよと、ある。

インストール手順
Run the BIOS update utility from Windows environment
1. Browse to the location where you downloaded the file and double-click the new file.
2. Windows System will auto restart and update BIOS while system startup screen.
3. After BIOS update finished, system will auto reboot to take effect.

ところが、A11 の Bios アップデートプログラムをダウンロードしてを実行すると、A5 に先にしろと言われる。

A5 でエラー!

じゃあということで、ダウンロードして実行する。

Alienware Aurora R4 System BIOS ドライバの詳細 | Dell 日本

インストール手順
1. Click the .exe in OS mode
2. Enter YES to update your BIOS.
3. After flash OK, please remember to restart your system.

と、でるが、A5 の Bios アップデートプログラムを実行すると、エラーがでて進まない。

MS-Dos でやるといいらしい。

調べていくと、free-dos の起動USBにファイルを書き足す方法と、ms-dos で行う方法が見つかった。

ms-dos の 起動USB を作成するほうが楽だと判断した。

MS-DOS 起動USB の作成

HP USB Disk Storage を使用する

HP USB Disk Storage を取得する。

起動情報は、Windows98 のものをダウンロードした。どこからか拾ってきた気がします。

フォーマットできない!?

Windows10で実行すると、Write protected と出る。

解除方法は youtube で見つかった。

※後述しますが、私は結局失敗してます

https://www.youtube.com/watch?v=NidagvFl5kI

Input these in order:
"diskpart" enter
"listdisk" enter
"select disk 1" enter (just don't choose wrong partition, notice the size partition)
"clean" enter
"convert mbr" enter

Biosファイルのリネーム

ファイル名の長さ制限「ファイル名(ベース名)部分が最大で8文字、拡張子部分が最大で3文字」らしいので、A5.exe, A11.exe などとリネームしておいた。

Biosファイルを設置

USBのRootディレクトリに置いた。

F12 から USB ブート

MS-DOS の起動までは行くが、A5を実行しても、プログラムが進まない。

しばらく待って、Ctrl + Alt + Del で抜け出した。

Windows7でサイド作成

Windowsを10から7に変えたから成功したのかは不明だが、Write protected などともでず、普通に終わった。

再度 Ms-dos で起動

起動し、A5 を実行。

進捗画面がちゃんと出て、1分足らずで終了。

動作確認

Windowsを通常起動し、正常に使用できることを確認した。

A11 にアップデート

再度 USB から MS-Dos で起動し、A11 を実行。正常に終わる。

再起動でとまった

y でリブートするが、けたたましいファンの音がするばかりで起動しない。

このことは、BBS でも報告があり、電源を切って入れ直すと2回目の起動で正常に進んだ・・・と書かれてあったので、しばらくまってみてから、電源を切って再起動した。

無事完了したように思われる。

opencv で 鮮鋭化

鮮鋭化 / アンシャープマスキング を行います。

チュートリアルには登場しないし、専用の関数も無いのですが、cvFilter2D で、kernel にマイナスを使用して適用することで実現するようです。

filter2D

使用するカーネル

0, −1, 0 −1, 5, −1, 0, −1, 0

−1, −1, −1 −1, 9, −1, −1, −1, −1

などです。

結果

f:id:pongsuke:20180327143435p:plainオリジナル

f:id:pongsuke:20180327143438p:plain4近傍

f:id:pongsuke:20180327143441p:plain8近傍

#!/usr/bin/env python
# -*- coding: utf-8 -*
import sys 
import cv2 
import numpy as np

def main():
    # BGR
    image = cv2.imread('img/um.02.png')

    cv2.namedWindow("original")
    cv2.moveWindow("original", 200, 200)
    cv2.imshow('original', image)

    kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]], np.float32)
    #kernel = np.array([[0,-1,0], [-1,5,-1], [0,-1,0]], np.float32)
    print(kernel)

    dst = cv2.filter2D(image, -1, kernel)

    cv2.namedWindow("result")
    cv2.moveWindow("result", 200, 400)
    cv2.imshow('result', dst)
    cv2.imwrite('img/um.k9.png', dst)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return 0

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass