イメージ・マジックで今一番アツいレンズマウントは?

矢野です。去年(2018年)から、フルサイズなミラーレスカメラが非常に盛り上がっていますね。これまで私は機動性重視で小型軽量なマイクロフォーサーズを愛用してきましたが、これだけにわかに盛り上がってくると、多少大きくても(マイクロフォーサーズもいつの間にかずいぶん大きいのが多くなってきたし)フルサイズについつい目移りしてしまうものです(お値段はがもうちょっとどうにかなっていただきたいものではありますが……)。個人的には、Lマウントのシグマのカメラがどんななのかが非常に気になります。 では、我らがイメージ・マジックで人気のカメラはどんなものなんでしょう? 今回は、社内のごくごく一部(?)で非常に盛り上がっているレンズマウントをご紹介しましょう。Sマウントです!

Sマウントとは

「Sマウント」と言っても、戦後から1950年代ごろまで製造されたニコンのレンズマウントのことではありません。そっちはそっちで面白そうですが、脱線は我慢。工業用とか、監視カメラ用の小型の規格です。「M12マウント」(内径が12mm)とも呼ばれるようです。
Sマウント用レンズ
レンズは単焦点です。側面に螺子が切ってあって、これの締め具合でフォーカスの調整をします。特にストッパーなども無く、奥までねじ込んじゃうとセンサーと多分ぶつかるのでちょっとコワいです。
Sマウント対応のカメラモジュール
同じSマウントに準拠していればレンズやモジュールの交換は可能ですから、カメラの用途や対象物との距離などによって適宜使い分けることもできます。

Sマウントのカメラで撮影する

レンズを取り付けたカメラモジュール(PCにはUSBケーブルで接続)
レンズのマウントの形式は、当然ですがカメラ制御そのものにはあまり影響しません。UVC(USB Video Class)に対応したカメラモジュールであれば、PCに接続するだけで基本的には使用できるようになります。WindowsならMedia FoundationやDirectShow、その他の画像を扱うライブラリ等からアクセス可能です。カメラモジュール独自の機能を使いたい場合は、カメラ専用のAPIを呼び出すことになります。 というわけで、「使うだけ」ならさほど難しくないSマウントのカメラですが、これをどう使うか、価値を生み出すように使えるかが私たちの腕の見せ所です。

「ブラックマーク」は縁の下の力持ち

はじめに

矢野です。小石川オフィスに引っ越してきて、1か月あまりが経ちました。小石川や、それに近い西片・本郷界隈は起伏が激しくて入り組んだ道が多く、引っ越し直後はランチの後にちょっと散歩するとすぐに迷子になっていたものです。それでもだんだんと脳内の地図が整理されてきて、かなり歩きやすくなってきました。

ブラックマークって何?

ちょっとググってみると、「ドリフト走行などで路面にできるタイヤの黒い跡」とか「汚点」とか、今年公開のそういうアクション映画があるとか、色々出てきます。ですが、私たちが扱っているブラックマークとは、「印刷用紙の裏側の黒い印」のことです。

ブラックマーク

ブラックマークの例。用紙を横切るような帯状のものや、紙面の中央に四角く描かれたものなど。

生産管理に使用する小さなラベルや完成品をお届けするための配送伝票などのシールの台紙となる剥離紙の裏側に印刷されている黒い印や帯のことです。シールとして貼る際に捨てられてしまうので、お客様の目に触れることはありません。いわば縁の下の力持ちですね。

何のために使うの?

私たちが取り扱うラベルプリンターには印字ヘッドの近くに光学式のセンサーが内蔵されていて、それで台紙の裏側をスキャンできます。ブラックマークを検知するまでは用紙を送り出して、検知したところで位置合わせ。そこから印刷を始めて、1枚分印刷できたら台紙ごとカットする(これもプリンターに内蔵されたカッターがやってくれます)。1枚ごとの長さが決まっているロール式のラベルを正確に取り扱うための、重要なマークです。

と、ある程度取り扱えるようになってから言うのは簡単ですが、プリンターと用紙がそれぞれ専用の組み合わせでない場合は、用紙の向き、サイズ、光学センサーの位置、検知の方式(透過式? 反射式?)、マークからの相対的な位置の設定などなど、いろいろな苦闘がありました。用紙のフィードがいつまでも止まらなかったり、おかしなところでちょん切られたり……。

形のないソフトウェアの世界と、プリンターやRFIDリーダーなどのハードウェア、印刷メディアなどの間を行ったり来たりしながら、私たちは開発の仕事をしています。

印刷しているのは、商品だけじゃありません

はじめに

こんにちは、イメージ・マジックの矢野です。入社から2か月が経過し、順調に机の上がゴチャゴチャしてきました。カメラが2台、バーコードプリンターが2台、小さなスピーカーが1台、さらにカードリーダーが1台、デスクの上に転がっています。

印刷しているもの

当社が印刷しているのは、Tシャツやパーカー、マグカップ、カーペットなどの製品そのものももちろんですが、それだけではお客様のお手元に製品を届けることはできません。生産工程でそれらを管理するためのラベルシールや、納品書、配送業者さんにお願いする送り状なども自社のシステムで印刷しています。当然といえば当然なのですが。

ラベルシールの印刷には、専用のプリンターを使用しています。私は転職してきて初めて触りました。ずんぐりむっくりでかわいい形ですが、言うことを聞かせるのはなかなか難しいです。プリンター専用のツールやライブラリを使ってバーコードや文字列や画像を出力するように指示することもできますが、プリンターの制御用コマンドを直接(「直接」とは言っても、通り抜けなければならないレイヤーは多数あります)送信することもできます。

ところで、「プリンターで何かを印刷する」というのはどういうことなのでしょう? それは文字列や画像、バーコードを印刷しなさいというコマンドの積み重ねです。ラベルシールにバーコードを印刷する場合には、最終的にたくさんのしましまが紙面に出力されるようなコマンドをアプリケーションで生成して、それをプリンターに送信する必要があるわけです。

たくさんのしましまを、どうやってプリンターに送信しましょうか?

  1. しましまを1本1本引くコマンドを生成して、順番に実行する
  2. バーコード全体の画像をPNGなどのラスター画像で生成して、画像を印刷するコマンドを実行する
  3. 「このデータ(ID)に対応するバーコードを、このバーコード規格を使ってイイ感じに生成してよ」とプリンターに任せるコマンドを実行する
  4. その他

1も2も3も正解ですが、1は特に厳しい。バーコードの仕様に従って、1本1本のしましまの太さと間隔をどうにかこうにかしなければなりません。2は割とよくあると思います。バーコード画像を生成するライブラリを使用すれば、割とサクっとできるでしょう。でも、せっかく専用のプリンターを使っているのですから、彼(彼女?)に任せてしまってみましょう。

イイ感じにやってもらう

Windowsで、Win32 APIを使って実装してみます。プリンターによろしくやってもらう代わりに、プリンター固有のお作法に従わなくてはなりません。ここでは、Zebra Technologies社のプリンタ向け言語、ZPL(Zebra Programming Language)のコマンドを実行しています。

int PrintRawCommand()
{
	HANDLE hPrinter;

	if (!OpenPrinter((LPSTR)"Printer Name", &hPrinter, NULL))
	{
		// エラー処理

		return FALSE;
	}

	DOC_INFO_1 docInfo;
	docInfo.pDocName = (LPSTR)"Barcode sample";
	docInfo.pOutputFile = NULL;
	docInfo.pDatatype = (LPSTR)"RAW";

	LPSTR command = (LPSTR)"^XA^FO40,40^BY3^BEN,40,Y,N^FD123456789012^FS^XZ";

	if (StartDocPrinter(hPrinter, 1, (LPBYTE)&docInfo))
	{
		if (StartPagePrinter(hPrinter))
		{
			DWORD writtenBytes;
			if (WritePrinter(hPrinter, command, strlen(command), &writtenBytes))
			{
				// 印刷成功時の処理
			}
			else
			{
				// エラー処理

				return FALSE;
			}
		}
		else
		{
			// エラー処理

			return FALSE;
		}
	}
	else
	{
		// エラー処理

		return FALSE;
	}

	EndPagePrinter(hPrinter);
	EndDocPrinter(hPrinter);
	ClosePrinter(hPrinter);

	return TRUE;
}

15行目で、プリンタへ送信するデータの形式をRAW(生=Zebraのプリンターが解するコマンドを直接送信する)に指定します。17行目の文字列が実際にプリンタへ送信されるZPLのコマンドです。レイアウト、フィールド、バーコードの表現形式(EAN-13)、バーコード化したいデータ(123456789012)などを、 ^ で始まるコマンドで指定します。

これの出力結果がこうなります。

EAN-13の詳細な仕様を隅々まで探らなくても、難しい画像操作系のAPIを駆使しなくても、美しいバーコードを得ることができました。

Node.jsのネイティブなアドオンを書く

はじめに

こんにちは。イメージ・マジックの矢野です。入社からもうすぐ1か月です。

Node.jsのアドオンを、何らかの理由でネイティブのコードで書かなければならないことがあります。Node.jsのエンジンであるV8のお作法に則って書くことになりますが、V8がバージョンアップして仕様が変われば、そのお作法も変わります。お作法が変わればアドオンの書き方も変えなければならず、毎度毎度書き直すのは大変。そこで、Node.jsのネイティブなアドオンの実装をイイ感じにラップして抽象化してくれる、NAN(Native Abstractions for Node.js)というものがつくられたとのこと(READMEの冒頭を読むと、クスリとさせられます)。もちろんNANを使わなくてむ作れるわけですが、せっかく便利なものがあるのですから、使わない手はありません。

準備

Node.jsのアドオンをつくるのですから、当然Node.jsはインストールされていないといけません。

NANはnode-gypでビルドするため、node-gypもインストールしておかなければいけません。さらにgypはPythonスクリプトなので、Pythonが入っていなければインストールしておかなければなりません。

ネイティブコードをビルドするために、コンパイラなども必要です。今回はWindowsを使って開発しているので、Visual Studio 2017をインストールしておきます。

作成

準備ができたところで、作業用のディレクトリを作成します。

mkdir hoge
cd hoge

NANをインストールします。

npm install --save nan

binding.gypを作成します。このテキストファイルには、アドオンの構成を記述します。ネイティブならではのアドオンをばっちり作り込むのはそれなりに大変なので、今回はOSのバージョンを取得するだけの簡単なものにしようと思います。

{
  "targets": [
    {
      "target_name": "getosversion",
      "sources": [
        "src/addon.cpp",
      ],
      "include_dirs": [
        "<!(node -e \"require('nan')\")",
      ],
    }
  ]
}

ソースファイルを格納するディレクトリ(src)をつくり、ソースファイルを形だけでも(空ファイルでOK)つくっておきます(src/addon.cpp)。

node-gypconfigureすると、上記の構成に従ってVisual StudioのC++プロジェクトやソリューションを生成してくれます。

node-gyp configure

buildディレクトリの下にいろいろファイルができています。

│  binding.gyp
│
├─build
│      binding.sln
│      config.gypi
│      getosversion.vcxproj
│      getosversion.vcxproj.filters
│
└─src
        addon.cpp

binding.slnを開くと、Visual Studioが起動しますので、addon.cppの中身を書いていきます。NANの恩恵を受けるには、ヘッダファイルnan.hをincludeしておく必要があります。
Win32 APIのGetVersion()を呼び出して、OSのバージョン情報を取得してみます。ちなみにこの関数は現在「非推奨」になっていますが、Win32がメインの記事ではないので、そのまま使ってしまいます(業務ではこんなことしませんよ)。

#include <sstream>
#include <nan.h>

NAN_METHOD(GetOsVersion)
{
	DWORD dwVersion = GetVersion();

	DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
	DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));

	DWORD dwBuild = 0;
	if (dwVersion < 0x80000000)
	{
		dwBuild = (DWORD)(HIWORD(dwVersion));
	}

	std::stringstream ss;
	ss << dwMajorVersion << "." << dwMinorVersion << "." << dwBuild;

	info.GetReturnValue().Set(Nan::New<v8::String>(ss.str()).ToLocalChecked());
}

NAN_MODULE_INIT(init)
{
	Nan::SetMethod(target, "GetOsVersion", GetOsVersion);
}

NODE_MODULE(getosversion, init)

ビルドします。

node-gyp build

もろもろビルドされます。肝心のアドオンは、build/Release/getosversion.nodeとして生成されます。

│  binding.gyp
│
├─build
│  │  binding.sln
│  │  config.gypi
│  │  getosversion.vcxproj
│  │  getosversion.vcxproj.filters
│  │
│  └─Release
│      │  getosversion.exp
│      │  getosversion.iobj
│      │  getosversion.ipdb
│      │  getosversion.lib
│      │  getosversion.map
│      │  getosversion.node
│      │  getosversion.pdb
│      │
│      └─obj
│          └─getosversion
│              │  addon.obj
│              │  vc141.pdb
│              │  win_delay_load_hook.obj
│              │
│              └─getosversion.tlog
│                      ... (省略) ...
│
└─src
        addon.cpp

これを実際に動かしてみましょう。テスト用コードをこんな感じで書いてみます(test.js)。

var addon = require('./build/Release/getosversion');

var version = addon.GetOsVersion();

console.log(result);

nodeコマンドから実行してみると、それらしい値が取れました。

node test.js
10.0.16299