ここ数年は各種の開発に忙しくかかりきりとなっており、久々の記事となってしまいました。読者の皆様には大変すみません。今回は自作した感度の良いディジタル・シュリーレン装置の話です。シュリーレン装置は流体や温風の流れ、空気の疎密などを可視化して詳しく観察できる、たいへん便利な装置です。昔は凹面鏡とナイフエッジなどで光学装置として作られていましたが、現代ではディジタル化されているのが普通です。勝手な考えに偏っているかもしれませんが、DIYで作れば観察に常時利用できますし、「必要な時にすぐ作って使う」という方法もあり得る程の手軽さです。今回は概要を説明し、そのうちに続きを書きたいと思います。
1. シュリーレン装置は何に使うの?
空気の流れを可視化、空気の疎密を可視化、温風・冷風の流れを可視化など、色々な目的に使われます。例えば自然の通風が要るセンサー用の小さな日除防水ケースの場合、野外ではともかくも無風の室内では通風が不足しないか心配です。そこで、設計確定前に容器の形の断面模型を作り、微風(0.005m/s未満)を側面にあてるなどして、内部の気体の流れを観察してみます。横から流す空気を僅かに(1℃)温めることで、空気の疎密の違いを利用して、感度の良いシュリーレン装置として可視化をすることができます。
2.断面模型を作る場合のサイズは?
断面模型のサイズは、空気通過部分については実物となるべく同サイズか少し大き目にします。その理由は次なのですが、理由にご興味のない方はもちろん無視されてください。
流体における「レイノルズの相似側」によって、模型の倍率を1/Nにする場合には、同じ流体を用いるのなら
レイノルズ数=流速x代表長さ/動粘性係数
を一定に保つ必要があります。同じ気体つまり同じ粘性なら、模型側での流速はN倍にしないと同じ挙動を示す模型とはならないからです。
次の写真は、左がセンサーを収める予定のケース(透明にして示しているが実際は白)、右が気体通路をほぼ同サイズにした断面模型です。断面模型の表裏には透明度の高い樹脂を貼ってあります。

上の写真で右の模型に、左からごく微かな温風を当ててシュリーレン装置で観察しているのが次です。

空気が通気スペース中を素直に出入り・移動している様子が、動画で細かい部分まで手に取るように観察できます。
そういうわけで、私の使用目的の場合はこのような小さな範囲の観察が多いため、視野は横10cmx縦5㎝程度に設定しています。用途に応じてはもちろん大きくできますが、装置(といっても単に1枚の板と風防用の薄板だけです)を置く場所なども考慮しないといけませんね。
3. 装置の構成と原理は?
かつては、凹面鏡などの光学系の材料を準備するのがたいへんでしたが、ディジタル・シュリーレン装置は、解像度の少し高いWebカメラが1つあればできます。原理としては、空気は温度や圧力によって疎密状態が変わりますので、その部分を通してみる背景の模様には、方向のブレが生じます。つまり、レンズを通じて見る虚像の位置がずれるのと同じことです。
そのための仕組みとして、カメラの他には背景にするための細かい模様があると便利です。私はA4用紙に細い黒線多数を、コンピュータに印刷させたものをそのまま繰り返して使っています。大きな範囲を対象にする場合は、自然の風景(ただし動きのない細かいもの)を使われる方もいるようですし、タブレットなどの比較的大きい精細なディスプレイ画面を使う方法もあるようです。
いずれにせよ、そういった細かい背景と、背景の手前半分ほどの距離に、空気に疎密が生じている状態の撮影対象が必要です。その疎密が作る背景の像のブレの大きさを計測して色付けしているものです。このため、画像をプログラムで映像の画素数よりは少ない数百x数百の要素に分け、それぞれの要素について元の背景模様の位置からのズレの大きさを読取った値をマトリクスとして作成します。そして各要素のブレの値に応じた色を付けるという仕組みにします。
もちろん「ブレの限界(閾値)より小さい値」のところは元の背景の画像のままにします。そのために、先に撮った背景と後で撮る画像には方向などの狂いが生じないよう、構造をしっかり作る必要があり、そうすれば敏感となり、任意の感度の設定も容易にできます。
次の写真はこれに使っているWebカメラですが、3年ほど前に海外サイトから購入した安価なものです。対物レンズの鏡筒で、10倍Zoom、手動絞り(Close~Open)、そしてピント合わせ(Near~∞)の調整ができますので、この目的にはうってつけです。

カメラ胴体の上に簡単な水平器を勝手に貼り付けた犯人は私です。
土台とする丈夫な木板(60x1000x25㎜)に、このカメラを大きなL金具と自由雲台でがっちりと取り付け、簡単にはブレないようにしています。その木板の先端に背景を貼った平板を取り付けます。撮影対象物をセットする場所の周囲には、薄板で作った簡素な風防を置くだけのしかけの構造です。
4. カメラのピントはどこに合わせる?どう撮影?
撮影する空気はカメラから背景までの距離の真ん中付近にしますが、ピントは背景に合わせる必要があります。なにせ背景の僅かなズレを撮影するわけなのですから。ですので、絞り値を少し絞って(穴を小さくつまりF値を大きくして)、撮影対象にもピントがある程度合うようにします。(なお、もし撮影する空気の位置と背景との距離が近すぎると虚像のブレが小さすぎます。)

これで動画を撮る際には、AVI形式2560x1440ピクセルで1~30fpsを選べるようにしています。そのような勝手な仕様で鮮明なAVI=motionJPEGで撮影できるソフトは、余り多くはありません。私は自作のPCプログラムで撮影しています。
Windowsの場合は、DirectShow経由で簡単に好きな撮影プログラムが作れます。AVI用CODECとしてはXVIDを使っています(繊細性、各種環境での互換性、ファイルサイズ面で適切です)。ごく簡単なAvi_cameraプログラム例は次です。この目的の録画だけをする、単純かつお馬鹿なその場しのぎのプログラムといえますが、一応載せておきます。カメラの各種調整が出来るプログラムがよいでしょうが、そちらはWindows標準の”カメラ”を使うのが賢いかと思います。
以下、2026.9.23追記:
AVI_cameraの単純なプログラムは次です。
# =========================================================================
# Simple AVI_camera for Schlieren videos V.01s Sep.20, 2026
# (for IMX335 USB Cam with 5-50mm Zoom, Aperture, & focus ctl,
# USB2.0 Video Cam SU200MB, or any industry-camera like these.
#
# Initial version: Jun.17,2024 (c) Akira Tominaga
# V01: added some line comments to share the program. Sep.20,2026
# Operations: 1)Reply camera # on the PC. 2)"Enter" to start capture.
# 3)Type "q" to stop capture, at the video window.
# *)To change variables, change the definitions below.
# Remarks:
# Author has copyright, but no responsibilities to guarantee
# or support for the operations.
# =========================================================================
import cv2 # computer vision lib.2
import os # to use Window's lib.
import re # to use search in Regular Expression
# ============================================================
# definitions
# ============================================================
SAVE_DIR = r"E:\PyUser\BOSpic\AVIcam" # output file path
WIDTH = 2560
HEIGHT = 1440
FPS = 5.0 # specify speed 1.0 ~ 30.0 fps
while True:
try:
CAMERA_NO = int(input("Camera No. (0 / 1 / 2) : "))
if CAMERA_NO in (0, 1, 2):
break
print("Please enter 0, 1 or 2.")
except ValueError:
print("Please enter a number.")
DISPLAY_WIDTH = 1280 # half size for display
DISPLAY_HEIGHT = 720 # half size for display
CODEC = "XVID" # CODEC to save AV
# ============================================================
# get sequence# to use as a file identifier
# ============================================================
def get_next_sequence(folder):
os.makedirs(folder, exist_ok=True)
pattern = re.compile(r"^CAM_(\d{4})\.avi$", re.IGNORECASE)
max_number = 0
for filename in os.listdir(folder):
match = pattern.match(filename)
if match:
number = int(match.group(1))
if number > max_number:
max_number = number
return max_number + 1
# ============================================================
# create file name
# ============================================================
sequence = get_next_sequence(SAVE_DIR)
filename = f"CAM_{sequence:04d}.avi"
filepath = os.path.join(SAVE_DIR, filename)
print("Saving file name:")
print(filepath)
# ============================================================
# open web camera
# using DirectShow of Windows
# ============================================================
cap = cv2.VideoCapture(CAMERA_NO, cv2.CAP_DSHOW)
if not cap.isOpened():
print("Error. Unable to open the camera.")
raise SystemExit
# ============================================================
# setting camera capture
# ============================================================
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
cap.set(cv2.CAP_PROP_FPS, FPS)
# confirm the values
actual_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_fps = cap.get(cv2.CAP_PROP_FPS)
print()
print("Camera settings")
print(f"Resolution : {actual_width} x {actual_height}")
print(f"FPS : {actual_fps:.2f}")
print()
# wait for keyboard
text = input("Push enter-key to start.. ")
# with enter key
print("Starting..")
# ============================================================
# AVI Writer
# ============================================================
fourcc = cv2.VideoWriter_fourcc(*CODEC)
writer = cv2.VideoWriter(
filepath,
fourcc,
FPS,
(WIDTH, HEIGHT)
)
if not writer.isOpened():
print("Error. Could not make AVI.")
cap.release()
raise SystemExit
# ============================================================
# start recording
# ============================================================
print("Recording starts. ")
print("Use q key to finish。")
print()
cv2.namedWindow("CAMERA", cv2.WINDOW_NORMAL)
cv2.resizeWindow("CAMERA", DISPLAY_WIDTH, DISPLAY_HEIGHT)
try:
while True:
ret, frame = cap.read()
if not ret:
print("Error. Unable to capture image.")
break
# ----------------------------------------------------
# Fix size to 2560x1440 (for dameoshi only)
# ----------------------------------------------------
if frame.shape[1] != WIDTH or frame.shape[0] != HEIGHT:
frame = cv2.resize(
frame,
(WIDTH, HEIGHT),
interpolation=cv2.INTER_LINEAR
)
# ----------------------------------------------------
# save to AVI
# 2560x1440
# ----------------------------------------------------
writer.write(frame)
# ----------------------------------------------------
# display to window 1280x720 (resized)
# ----------------------------------------------------
display_frame = cv2.resize(
frame,
(DISPLAY_WIDTH, DISPLAY_HEIGHT),
interpolation=cv2.INTER_AREA
)
cv2.imshow("CAMERA", display_frame)
# ----------------------------------------------------
# q_key @ video window to finish caturing
# ----------------------------------------------------
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
finally:
writer.release()
cap.release()
cv2.destroyAllWindows()
print()
print("Recording finished.")
print("AVI saved to :")
print(filepath)
>
今回は、とりあえずこのくらいにさせていただきます。今後また時間のあるときに、別記事で具体的に説明できればと思います。少しずつですみませんがお役に立てば幸い。
©2026 Akira Tominaga, All rights reserved.






















この季節は天気予報が頻繁に変わるのに気づきます。PCや




















