2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spresense ズームレンズ対応HDRカメラを動作させてみた

Last updated at Posted at 2024-12-22

前回の記事でズームレンズのモーター制御に成功しました。転がっていたデータシートがあっていてよかった。今回はいよいよHDRカメラとあわせてカメラとして動作するか買う人をしていきます。

SPRESENSE HDRカメラズームレンズの接続

Spresense HDRカメラとしての動作を確認するために、LCDとSDカード、そして画像を保存するためのシャッターボタンを追加しました。SDカードとLCDとの接続には拡張ボードを使います。

image.png

実際の接続の様子はこちら。かなりビジーになってしまいました。

DSC02605.JPG

DSC02606.JPG

SPRESENSE HDRカメラズームレンズのプログラム

ズームとフォーカスは可変抵抗で調整します。シャッターを押すとBMP画像でSDカードに保存します。

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arch/cxd56xx/scu.h>
#include <arch/cxd56xx/adc.h>
#include <Camera.h>
#include <Stepper.h>
#include <Adafruit_ILI9341.h>
#include <BmpImage.h>
#include <SDHCI.h>

// D27 - Focus A+ (BLACK)
// D28 - Focus A- (BLUE) 
// D01 - Focus B+ (RED)
// D00 - Focus B- (WHITE)

// D23 - Zoom A+ (ORANGE)
// D24 - Zoom A- (GREEN)
// D25 - Zoom B+ (YELLOW)
// D26 - Zoom B- (PURPLE)

#define FOCUS_AP (27)
#define FOCUS_AN (28)
#define FOCUS_BP (1)
#define FOCUS_BN (0)

#define ZOOM_AP (23)
#define ZOOM_AN (24)
#define ZOOM_BP (25)
#define ZOOM_BN (26)

#define TFT_DC  9
#define TFT_CS  10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
BmpImage bmp;
SDClass theSD;

const int turnSteps = 1607;  // 0.224 deg/step
const int zoomMaxStep = 2342;
const int focusMaxStep = 2342;
const int rpm = 20;

Stepper FocusStepper(turnSteps, FOCUS_AP, FOCUS_AN, FOCUS_BP, FOCUS_BN);
Stepper ZoomStepper(turnSteps, ZOOM_AP, ZOOM_AN, ZOOM_BP, ZOOM_BN);

int fd_a2;
int fd_a3;

const int intPin = 21;
bool bButtonPressed = false;
void changeState() {
  bButtonPressed = true;
}

void setup() {
  Serial.begin(115200);

  tft.begin();
  tft.setRotation(3);

  theCamera.begin();
  theCamera.setStillPictureImageFormat(
    CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V, 
    CAM_IMAGE_PIX_FMT_RGB565);

  while (!theSD.begin()) { Serial.println("Insert SD Card"); } 
  pinMode(intPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(intPin) ,changeState ,FALLING);

  // initialize LLPADC 2 and 3
  fd_a2 = open("/dev/lpadc2", O_RDONLY);
  fd_a3 = open("/dev/lpadc3", O_RDONLY);
  ioctl(fd_a2, SCUIOC_SETFIFOMODE, 1);
  ioctl(fd_a3, SCUIOC_SETFIFOMODE, 1);
  ioctl(fd_a2, ANIOC_CXD56_FIFOSIZE, 2);
  ioctl(fd_a3, ANIOC_CXD56_FIFOSIZE, 2);
  ioctl(fd_a2, ANIOC_CXD56_START, 0);
  ioctl(fd_a3, ANIOC_CXD56_START, 0);

  FocusStepper.setSpeed(rpm);
  ZoomStepper.setSpeed(rpm);

  Serial.println("move home position");
  FocusStepper.step(focusMaxStep);
  ZoomStepper.step(zoomMaxStep);
  Serial.println("home position");
  delay(1000);
}

void loop() {
  static int zoom_pos = zoomMaxStep;
  static int focus_pos = focusMaxStep;

  int16_t val_z;
  int16_t val_f;
  while(read(fd_a2, &val_z, sizeof(int16_t)) == 0);
  while(read(fd_a3, &val_f, sizeof(int16_t)) == 0);

  val_z = map(val_z, -0x7fff, 0x7fff, 0, zoomMaxStep);
  val_f = map(val_f, -0x7fff, 0x7fff, 0, focusMaxStep);

  Serial.println("Zoom: " + String(val_z));
  Serial.println("Focus: " + String(val_f));

  int zoom_step = val_z - zoom_pos;
  int focus_step = val_f - focus_pos;
  if (abs(zoom_step) > 100 || abs(focus_step) > 100) {
    zoom_pos = val_z;
    focus_pos = val_f;
    ZoomStepper.step(zoom_step);
    FocusStepper.step(focus_step);
  }

  CamImage img = theCamera.takePicture();
  if (img.isAvailable()) {
    tft.drawRGBBitmap(0, 0, (uint16_t*)img.getImgBuff(), CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V);
    if (bButtonPressed) {
      static int g_counter = 200;
      bmp.begin(BmpImage::BMP_IMAGE_RGB565, CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V, img.getImgBuff());
      bmp.alignImageLine(false); 
      char filename[16] = {};
      sprintf(filename, "rgb16%03d.bmp", g_counter++);
      if (theSD.exists(filename)) theSD.remove(filename);
      File myFile = theSD.open(filename, FILE_WRITE);
      myFile.write(bmp.getBmpBuff(), bmp.getBmpSize());
      myFile.close();
      bmp.end();
      Serial.println("Saved as " + String(filename));    
      bButtonPressed = false;
    }
  }

}

撮影結果

フォーカスを手動で合わすのはちょっと難儀しましたが、慣れてくるとなんとかなりますね。今後、オートフォーカスの実装を試してみたいと思います。倍率をかえた画像をいくつか撮影をしましたので、その結果をこちらに披露します。被写体は私の大好きなトラスト・イカちゃんです。

rgb16200.png
最大ズーム

rgb16004.png
フォーカスが甘かった (´・ω・`)

rgb16010.png

rgb16013.png

rgb16016.png

rgb16100.png
最大ワイドでフォーカス合わず

最大ワイドのケースでは、被写体との距離が近すぎてフォーカスがあいませんでした。レンズの特性をよく考えて制御をする必要がありますね。

こうして画像を並べてみると、かなりズームできるのがわかります。これは、かなり使えそうです。HDRカメラなら監視カメラとしてもばっちりです。オートフォーカスやパン・チルト機能をつければ立派なカメラになりそうですね。

そのあたりは今後検討していきたいと思います。

関連記事
Spresense HDRカメラのズームフォーカスレンズ用のフォルダを作る
Spresense HDRカメラ用のズームフォーカスレンズのモーターの仕様を確認する
Spresense HDRカメラ用のズームフォーカスレンズのモーターを制御する

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?