Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Software/LMSourceCode/ImageProcessing/cam2_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ bool Camera2Thread::init_pipeline() {
options->Set().info_text = "";

const CameraHardware::CameraModel camera_model = GolfSimCamera::kSystemSlot2CameraType;
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono) {
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono ||
camera_model != CameraHardware::CameraModel::Mira220_Mono) {
options->Set().denoise = "cdn_off";
} else {
options->Set().denoise = "auto";
Expand Down
46 changes: 42 additions & 4 deletions Software/LMSourceCode/ImageProcessing/camera_hardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ namespace golf_sim {
{ "3", CameraModel::PiHQ },
{ "4", CameraModel::PiGS },
{ "5", CameraModel::InnoMakerIMX296GS_Mono },
{ "6", CameraModel::Mira220_Mono },
{ "100", CameraModel::kCameraUnknown },
};
if (camera_table.count(model_enum_value_string) == 0)
Expand Down Expand Up @@ -133,7 +134,7 @@ namespace golf_sim {


bool CameraHardware::camera_is_mono() const {
return (camera_model_ == CameraModel::InnoMakerIMX296GS_Mono);
return (camera_model_ == CameraModel::InnoMakerIMX296GS_Mono || camera_model_ == CameraModel::Mira220_Mono);
}


Expand Down Expand Up @@ -236,17 +237,17 @@ namespace golf_sim {
}

// This section deals with the common characteristics of some of the cameras
if (model == PiGS ||
if (model == PiGS ||
model == InnoMakerIMX296GS_Mono) {

GS_LOG_TRACE_MSG(trace, "Initializing with a PiGS or InnoMakerIMX296GS_Mono camera." );
GS_LOG_TRACE_MSG(trace, "Initializing with a PiGS or InnoMakerIMX296GS_Mono camera.");
// Sensor pixel width is 3.45uM square? No - 6.33mm diagonal. It appears that
// the actual width is the full resolution (1456) * 3.4uM = 4.95mm,
// Not simply the diagonal sensor width

sensor_width_ = (float)5.077365371; // 4.45; // (1456.0 * 3.4) / 1000; // = 4.95; // In mm 6.3 / sqrt(2.0); // TBD - Confirm math from diagonal measurement
sensor_height_ = (float)3.789078635; // 4.45; //(1088.0 * 3.4) / 1000; // In mm 6.3 / sqrt(2.0);

if (resolution_x_override_ > 0 && resolution_y_override_ > 0) {
resolution_x_ = resolution_x_override_;
resolution_y_ = resolution_y_override_;
Expand All @@ -263,6 +264,43 @@ namespace golf_sim {
video_resolution_y_ = 1080;

GS_LOG_TRACE_MSG(trace, "Video resolution (x,y) is: " + std::to_string(video_resolution_x_) + "/" + std::to_string(video_resolution_y_) + ".");
}

if (model == Mira220_Mono) {

// See https://look.ams-osram.com/m/7591efdbe4af32dc/original/Mira220-1-2-7-2-2-MP-NIR-enhanced-global-shutter-image-sensor.pdf for details

GS_LOG_TRACE_MSG(trace, "Initializing with a Mira220_Mono - based camera.");
// Sensor pixel width is 3.45uM square? No - 6.33mm diagonal. It appears that
// the actual width is the full resolution (1456) * 3.4uM = 4.95mm,
// Not simply the diagonal sensor width

sensor_width_ = (float)4.464; // 2.79um pixel size * 1600
sensor_height_ = (float)3.906; // 2.79um pixel size * 1400

if (resolution_x_override_ > 0 && resolution_y_override_ > 0) {
resolution_x_ = resolution_x_override_;
resolution_y_ = resolution_y_override_;
}
else {
// Defaults
resolution_x_ = 1600;
resolution_y_ = 1400;
}

// We ahve not tested .
video_resolution_x_ = resolution_x_;
video_resolution_y_ = resolution_y_;

GS_LOG_TRACE_MSG(trace, "Video resolution (x,y) is: " + std::to_string(video_resolution_x_) + "/" + std::to_string(video_resolution_y_) + ".");
}


// Ball radius parameters are common to most all of our potential cameras
if (model == PiGS ||
model == InnoMakerIMX296GS_Mono ||
model == Mira220_Mono) {


// Attempt to get the expected ball radius from the .json file
std::string ball_radius_pixels_at_40cm_name = "kExpectedBallRadiusPixelsAt40cmCamera" + std::string(camera_number == GsCameraNumber::kGsCamera1 ? "1" : "2");
Expand Down
1 change: 1 addition & 0 deletions Software/LMSourceCode/ImageProcessing/camera_hardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace golf_sim {
PiHQ = 3,
PiGS = 4,
InnoMakerIMX296GS_Mono = 5,
Mira220_Mono = 6,
kCameraUnknown = 100
};

Expand Down
10 changes: 7 additions & 3 deletions Software/LMSourceCode/ImageProcessing/libcamera_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,8 +753,10 @@ bool ConfigureLibCameraOptions(const GolfSimCamera& camera, RPiCamEncoder& app,

options->Set().timeout.set("100000s");

// TBD - Internet suggests that the Mira220 also needs cdn_off
const CameraHardware::CameraModel camera_model = GolfSimCamera::kSystemSlot1CameraType;
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono) {
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono &&
camera_model != CameraHardware::CameraModel::Mira220_Mono) {
options->Set().denoise = "cdn_off";
}
else {
Expand Down Expand Up @@ -1119,7 +1121,8 @@ LibcameraJpegApp* ConfigureForLibcameraStill(const GolfSimCamera& camera) {
options->Set().contrast = camera_contrast;
options->Set().timeout.set("100000s");
const CameraHardware::CameraModel camera_model = GolfSimCamera::kSystemSlot1CameraType;
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono) {
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono &&
camera_model != CameraHardware::CameraModel::Mira220_Mono) {
options->Set().denoise = "cdn_off";
}
else {
Expand Down Expand Up @@ -1419,7 +1422,8 @@ bool WaitForCam2Trigger(cv::Mat& return_image) {
// JPMOD
options->Set().timeout.set("100000s"); // Wait forever for external trigger
const CameraHardware::CameraModel camera_model = GolfSimCamera::kSystemSlot1CameraType;
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono) {
if (camera_model != CameraHardware::CameraModel::InnoMakerIMX296GS_Mono &&
camera_model != CameraHardware::CameraModel::Mira220_Mono) {
options->Set().denoise = "cdn_off";
}
else {
Expand Down
20 changes: 19 additions & 1 deletion Software/LMSourceCode/ImageProcessing/libcamera_jpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ void SetExternalTrigger(bool& flag) {
return;
}
}

if (!flag && camera_model == gs::CameraHardware::CameraModel::Mira220_Mono) {

flag = true;

std::string trigger_mode_command = "$PITRAC_ROOT/ImageProcessing/CameraTools/NEED_EXTERNAL_TRIGGER_UTILITY 4 1";

GS_LOG_TRACE_MSG(trace, "ball_flight_camera_event_loop - Camera 2 trigger_mode_command = " + trigger_mode_command);
int command_result = system(trigger_mode_command.c_str());

if (command_result != 0) {
GS_LOG_TRACE_MSG(trace, "system(trigger_mode_command) failed.");
return;
}
}

}

// Run the triggered capture event loop on an already-opened camera.
Expand All @@ -101,7 +117,9 @@ bool cam2_run_event_loop(LibcameraJpegApp& app, cv::Mat& returnImg, bool send_pr
// If appropriate, add the time we allow to setup external trigginer for the InnoMaker cameras
const gs::CameraHardware::CameraModel camera_model = gs::GolfSimCamera::kSystemSlot2CameraType;

if (camera_model == gs::CameraHardware::CameraModel::InnoMakerIMX296GS_Mono) {
// TBD - May need a separate pause time for the Mira220 camera, but for now, we'll assume it's the same as the InnoMaker IMX296GS Mono camera
if (camera_model == gs::CameraHardware::CameraModel::InnoMakerIMX296GS_Mono ||
camera_model == gs::CameraHardware::CameraModel::Mira220_Mono) {
kQuiesceTimeMs += gs::PulseStrobe::kPauseToSetUpInnoMakerExternalTriggerMilliseconds;
}

Expand Down
2 changes: 2 additions & 0 deletions Software/LMSourceCode/ImageProcessing/pulse_strobe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,8 @@ namespace golf_sim {
}
}

// NOTE - We're not yet sure if a Mira220-based sensor will need any priming pulses. However, it should probably work similar to the IMX296

GS_LOG_TRACE_MSG(trace, "Sent " + std::to_string(kNumberPrimingPulses) + " initial priming pulses. About to pause for " +
std::to_string(kPauseBeforeReadyForFinalPrimingPulseMs) + " milliSeconds before sending penultimate priming pulse.");

Expand Down
6 changes: 4 additions & 2 deletions Software/web-server/configurations.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@
"2": "Pi Camera v2 - IMX219 sensor (DEPRECATED)",
"3": "Pi HQ Camera - IMX477 sensor (DEPRECATED)",
"4": "Pi Global Shutter - IMX296 Color",
"5": "InnoMaker IMX296 - Mono sensor (RECOMMENDED)"
"5": "InnoMaker IMX296 - Mono sensor (RECOMMENDED)",
"6": "Osram Mira220 - Mono sensor (EXPERIMENTAL)"
},
"default": "5",
"requiresRestart": true,
Expand Down Expand Up @@ -391,7 +392,8 @@
"2": "Pi Camera v2 - IMX219 sensor (DEPRECATED)",
"3": "Pi HQ Camera - IMX477 sensor (DEPRECATED)",
"4": "Pi Global Shutter - IMX296 Color",
"5": "InnoMaker IMX296 - Mono sensor (RECOMMENDED)"
"5": "InnoMaker IMX296 - Mono sensor (RECOMMENDED)",
"6": "Osram Mira220 - Mono sensor (EXPERIMENTAL)"
},
"default": "5",
"requiresRestart": true,
Expand Down
2 changes: 1 addition & 1 deletion Software/web-server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
# Locked to defeat AE/AWB/tuning drift across calibration frames (sub-pixel
# corner bias). Tuning file matches production rcPi5GS.sh; shutter is shorter
# than production (11 vs 20 ms) to limit hand-tremor blur.
RPICAM_TUNING_FILE = "/usr/share/libcamera/ipa/rpi/pisp/imx296_noir.json"
RPICAM_TUNING_FILE = "/usr/share/libcamera/ipa/rpi/pisp/imx296_noir.json" # NOTE - Mira220 will need a different tuning file. For now, folks can just put the Mira220 file in this file
RPICAM_CAL_SHUTTER_US = 11000
RPICAM_CAL_GAIN = 1.3

Expand Down
Loading