cl-stitch: support 4k resolution mode
* tune 4k parameters for video stream
* add debug information to make it easier for qualiy tuning
* support framerate options in test-image-stitching via OpenCV codec
* gst-launch-1.0 cmdline:
$ gst-launch-1.0 filesrc location=input.nv12 \
! videoparse format=nv12 width=4096 height=2048 framerate=24/1 \
! xcamfilter copy-mode=1 enable-stitch=true stitch-scale=local \
stitch-fisheye-map=true stitch-fm-ocl=true stitch-res-mode=4k \
! video/x-raw, foramt=NV12, width=4096, height=2048 \
! queue ! vaapih264enc rate-control=cbr \
! tcpclientsink host="host-ip" port=3000 blocksize=1024000 sync=false
* test-image-stitching cmdline:
$ test-image-stitching --input input.nv12 --output output.mp4 \
--input-w 4096 --input-h 2048 --output-w 4096 --output-h 2048 \
--scale-mode local --enable-fisheyemap --fm-ocl true \
--res-mode 4k --framerate 24.0 --save true
Signed-off-by: Wind Yuan <[email protected]>
diff --git a/capi/context_priv.cpp b/capi/context_priv.cpp
index 82085ac..a1a3b8f 100644
--- a/capi/context_priv.cpp
+++ b/capi/context_priv.cpp
@@ -210,9 +210,13 @@
return NULL;
}
+ CLStitchResMode res_mode = CLStitchRes1080P;
+ if (_res_mode == StitchRes4K)
+ res_mode = CLStitchRes4K;
+
SmartPtr<CLImage360Stitch> image_360 =
- create_image_360_stitch(
- context, _need_seam, _scale_mode, _fisheye_map).dynamic_cast_ptr<CLImage360Stitch> ();
+ create_image_360_stitch (context, _need_seam,
+ _scale_mode, _fisheye_map, res_mode).dynamic_cast_ptr<CLImage360Stitch> ();
XCAM_FAIL_RETURN (ERROR, image_360.ptr (), NULL, "create image stitch handler failed");
image_360->set_output_size (sttch_width, sttch_height);
XCAM_LOG_INFO ("stitch output size width:%d height:%d", sttch_width, sttch_height);
diff --git a/capi/context_priv.h b/capi/context_priv.h
index 5088f53..cbb67f2 100644
--- a/capi/context_priv.h
+++ b/capi/context_priv.h
@@ -159,12 +159,19 @@
: public ContextBase
{
public:
+ enum StitchResMode {
+ StitchRes1080P = 0,
+ StitchRes4K
+ };
+
+public:
StitchContext ()
: ContextBase (HandleTypeStitch)
, _need_seam (false)
, _fisheye_map (false)
, _fm_ocl (false)
, _scale_mode (CLBlenderScaleLocal)
+ , _res_mode (StitchRes1080P)
{}
virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context);
@@ -174,6 +181,7 @@
bool _fisheye_map;
bool _fm_ocl;
CLBlenderScaleMode _scale_mode;
+ StitchResMode _res_mode;
};
#endif //XCAM_CONTEXT_PRIV_H
diff --git a/cl_kernel/kernel_gauss_lap_pyramid.cl b/cl_kernel/kernel_gauss_lap_pyramid.cl
index 2457f42..f9067c0 100644
--- a/cl_kernel/kernel_gauss_lap_pyramid.cl
+++ b/cl_kernel/kernel_gauss_lap_pyramid.cl
@@ -246,12 +246,13 @@
#if !PYRAMID_UV
step_x = 0.125f / output_width;
- out_data = read_scale_y (input, sampler, normCoor, step_x) * 256.0f;
+ out_data = read_scale_y (input, sampler, normCoor, step_x) * 255.0f;
#else
step_x = 0.25f / output_width;
- out_data = read_scale_uv (input, sampler, normCoor, step_x) * 256.0f;
+ out_data = read_scale_uv (input, sampler, normCoor, step_x) * 255.0f;
#endif
+ out_data = clamp (out_data + 0.5f, 0.0f, 255.0f);
write_imageui (output, (int2)(g_x + out_offset_x, g_y), convert_uint4(as_ushort4(convert_uchar8(out_data))));
}
diff --git a/modules/ocl/cl_image_360_stitch.cpp b/modules/ocl/cl_image_360_stitch.cpp
index 0e8a33d..13206c2 100644
--- a/modules/ocl/cl_image_360_stitch.cpp
+++ b/modules/ocl/cl_image_360_stitch.cpp
@@ -100,50 +100,125 @@
return true;
}
+#if HAVE_OPENCV
+static CVFMConfig
+get_fm_default_config (CLStitchResMode res_mode)
+{
+ CVFMConfig config;
+
+ switch (res_mode) {
+ case CLStitchRes1080P: {
+ config.sitch_min_width = 56;
+ config.min_corners = 8;
+ config.offset_factor = 0.8f;
+ config.delta_mean_offset = 5.0f;
+ config.max_adjusted_offset = 12.0f;
+
+ break;
+ }
+ case CLStitchRes4K: {
+ config.sitch_min_width = 160;
+ config.min_corners = 8;
+ config.offset_factor = 0.8f;
+ config.delta_mean_offset = 5.0f;
+ config.max_adjusted_offset = 12.0f;
+
+ break;
+ }
+ default:
+ XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode);
+ break;
+ }
+
+ return config;
+}
+#endif
+
static CLStitchInfo
-get_default_stitch_info ()
+get_default_stitch_info (CLStitchResMode res_mode)
{
CLStitchInfo stitch_info;
- stitch_info.merge_width[0] = 56;
- stitch_info.merge_width[1] = 56;
+ switch (res_mode) {
+ case CLStitchRes1080P: {
+ stitch_info.merge_width[0] = 56;
+ stitch_info.merge_width[1] = 56;
- stitch_info.crop[0].left = 96;
- stitch_info.crop[0].right = 96;
- stitch_info.crop[0].top = 0;
- stitch_info.crop[0].bottom = 0;
- stitch_info.crop[1].left = 96;
- stitch_info.crop[1].right = 96;
- stitch_info.crop[1].top = 0;
- stitch_info.crop[1].bottom = 0;
+ stitch_info.crop[0].left = 96;
+ stitch_info.crop[0].right = 96;
+ stitch_info.crop[0].top = 0;
+ stitch_info.crop[0].bottom = 0;
+ stitch_info.crop[1].left = 96;
+ stitch_info.crop[1].right = 96;
+ stitch_info.crop[1].top = 0;
+ stitch_info.crop[1].bottom = 0;
- stitch_info.fisheye_info[0].center_x = 480.0f;
- stitch_info.fisheye_info[0].center_y = 480.0f;
- stitch_info.fisheye_info[0].wide_angle = 202.8f;
- stitch_info.fisheye_info[0].radius = 480.0f;
- stitch_info.fisheye_info[0].rotate_angle = -90.0f;
- stitch_info.fisheye_info[1].center_x = 1440.0f;
- stitch_info.fisheye_info[1].center_y = 480.0f;
- stitch_info.fisheye_info[1].wide_angle = 202.8f;
- stitch_info.fisheye_info[1].radius = 480.0f;
- stitch_info.fisheye_info[1].rotate_angle = 89.4f;
+ stitch_info.fisheye_info[0].center_x = 480.0f;
+ stitch_info.fisheye_info[0].center_y = 480.0f;
+ stitch_info.fisheye_info[0].wide_angle = 202.8f;
+ stitch_info.fisheye_info[0].radius = 480.0f;
+ stitch_info.fisheye_info[0].rotate_angle = -90.0f;
+ stitch_info.fisheye_info[1].center_x = 1440.0f;
+ stitch_info.fisheye_info[1].center_y = 480.0f;
+ stitch_info.fisheye_info[1].wide_angle = 202.8f;
+ stitch_info.fisheye_info[1].radius = 480.0f;
+ stitch_info.fisheye_info[1].rotate_angle = 89.4f;
+
+ break;
+ }
+ case CLStitchRes4K: {
+ stitch_info.merge_width[0] = 160;
+ stitch_info.merge_width[1] = 160;
+
+ stitch_info.crop[0].left = 64;
+ stitch_info.crop[0].right = 64;
+ stitch_info.crop[0].top = 0;
+ stitch_info.crop[0].bottom = 0;
+ stitch_info.crop[1].left = 64;
+ stitch_info.crop[1].right = 64;
+ stitch_info.crop[1].top = 0;
+ stitch_info.crop[1].bottom = 0;
+
+ stitch_info.fisheye_info[0].center_x = 1024.0f;
+ stitch_info.fisheye_info[0].center_y = 1024.0f;
+ stitch_info.fisheye_info[0].wide_angle = 195.0f;
+ stitch_info.fisheye_info[0].radius = 1040.0f;
+ stitch_info.fisheye_info[0].rotate_angle = 0.0f;
+
+ stitch_info.fisheye_info[1].center_x = 3072.0f;
+ stitch_info.fisheye_info[1].center_y = 1016.0f;
+ stitch_info.fisheye_info[1].wide_angle = 192.0f;
+ stitch_info.fisheye_info[1].radius = 1040.0f;
+ stitch_info.fisheye_info[1].rotate_angle = 0.4f;
+
+ break;
+ }
+ default:
+ XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode);
+ break;
+ }
return stitch_info;
}
-CLImage360Stitch::CLImage360Stitch (SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode)
+CLImage360Stitch::CLImage360Stitch (
+ SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, CLStitchResMode res_mode)
: CLMultiImageHandler ("CLImage360Stitch")
, _context (context)
, _output_width (0)
, _output_height (0)
- , _is_stitch_inited (false)
, _scale_mode (scale_mode)
+ , _is_stitch_inited (false)
{
xcam_mem_clear (_merge_width);
#if HAVE_OPENCV
_feature_match = new CVFeatureMatch (context);
XCAM_ASSERT (_feature_match.ptr ());
+
+ _feature_match->set_config (get_fm_default_config (res_mode));
+#else
+ XCAM_UNUSED (res_mode);
#endif
}
@@ -530,8 +605,6 @@
CLImage360Stitch::prepare_parameters (SmartPtr<DrmBoBuffer> &input, SmartPtr<DrmBoBuffer> &output)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
- if (!_is_stitch_inited)
- init_stitch_info (get_default_stitch_info ());
ret = prepare_fisheye_parameters (input, output);
STITCH_CHECK (ret, "prepare fisheye parameters failed");
@@ -670,15 +743,14 @@
}
SmartPtr<CLImageHandler>
-create_image_360_stitch (
- SmartPtr<CLContext> &context, bool need_seam,
- CLBlenderScaleMode scale_mode, bool fisheye_map)
+create_image_360_stitch (SmartPtr<CLContext> &context, bool need_seam,
+ CLBlenderScaleMode scale_mode, bool fisheye_map, CLStitchResMode res_mode)
{
const int layer = 2;
const bool need_uv = true;
SmartPtr<CLFisheyeHandler> fisheye;
SmartPtr<CLBlender> left_blender, right_blender;
- SmartPtr<CLImage360Stitch> stitch = new CLImage360Stitch (context, scale_mode);
+ SmartPtr<CLImage360Stitch> stitch = new CLImage360Stitch (context, scale_mode, res_mode);
XCAM_ASSERT (stitch.ptr ());
for (int index = 0; index < ImageIdxCount; ++index) {
@@ -709,6 +781,7 @@
}
}
+ stitch->init_stitch_info (get_default_stitch_info (res_mode));
return stitch;
}
diff --git a/modules/ocl/cl_image_360_stitch.h b/modules/ocl/cl_image_360_stitch.h
index 94dc118..bfbbcb4 100644
--- a/modules/ocl/cl_image_360_stitch.h
+++ b/modules/ocl/cl_image_360_stitch.h
@@ -31,6 +31,11 @@
namespace XCam {
+enum CLStitchResMode {
+ CLStitchRes1080P,
+ CLStitchRes4K
+};
+
enum ImageIdx {
ImageIdxMain,
ImageIdxSecondary,
@@ -94,7 +99,8 @@
: public CLMultiImageHandler
{
public:
- explicit CLImage360Stitch (SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode);
+ explicit CLImage360Stitch (
+ SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, CLStitchResMode res_mode);
bool init_stitch_info (CLStitchInfo stitch_info);
void set_output_size (uint32_t width, uint32_t height) {
@@ -154,16 +160,18 @@
ImageMergeInfo _img_merge_info[ImageIdxCount];
Rect _overlaps[ImageIdxCount][2]; // 2=>Overlap0 and overlap1
- bool _is_stitch_inited;
-
CLBlenderScaleMode _scale_mode;
SmartPtr<BufferPool> _scale_buf_pool;
+
+ CLStitchResMode _res_mode;
+
+ bool _is_stitch_inited;
};
SmartPtr<CLImageHandler>
create_image_360_stitch (
- SmartPtr<CLContext> &context, bool need_seam = false,
- CLBlenderScaleMode scale_mode = CLBlenderScaleLocal, bool fisheye_map = false);
+ SmartPtr<CLContext> &context, bool need_seam = false, CLBlenderScaleMode scale_mode = CLBlenderScaleLocal,
+ bool fisheye_map = false, CLStitchResMode res_mode = CLStitchRes1080P);
}
diff --git a/modules/ocl/cl_post_image_processor.cpp b/modules/ocl/cl_post_image_processor.cpp
index aa7e425..001ee62 100644
--- a/modules/ocl/cl_post_image_processor.cpp
+++ b/modules/ocl/cl_post_image_processor.cpp
@@ -61,6 +61,7 @@
, _stitch_scale_mode (CLBlenderScaleLocal)
, _stitch_width (0)
, _stitch_height (0)
+ , _stitch_res_mode (0)
{
XCAM_LOG_DEBUG ("CLPostImageProcessor constructed");
}
@@ -386,9 +387,8 @@
/* image stitch */
image_handler =
- create_image_360_stitch (
- context, _stitch_enable_seam,
- _stitch_scale_mode, _stitch_fisheye_map);
+ create_image_360_stitch (context, _stitch_enable_seam,
+ _stitch_scale_mode, _stitch_fisheye_map, (CLStitchResMode) _stitch_res_mode);
_stitch = image_handler.dynamic_cast_ptr<CLImage360Stitch> ();
XCAM_FAIL_RETURN (
WARNING,
@@ -497,7 +497,7 @@
bool
CLPostImageProcessor::set_image_stitch (
bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map,
- bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height)
+ bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode)
{
XCAM_ASSERT (scale_mode < CLBlenderScaleMax);
@@ -511,6 +511,7 @@
_stitch_fisheye_map = enable_fisheye_map;
_stitch_width = stitch_width;
_stitch_height = stitch_height;
+ _stitch_res_mode = res_mode;
#if HAVE_OPENCV
_stitch_fm_ocl = fm_ocl;
diff --git a/modules/ocl/cl_post_image_processor.h b/modules/ocl/cl_post_image_processor.h
index 42f9e46..bb471e5 100644
--- a/modules/ocl/cl_post_image_processor.h
+++ b/modules/ocl/cl_post_image_processor.h
@@ -93,7 +93,7 @@
virtual bool set_image_warp (bool enable);
virtual bool set_image_stitch (
bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map,
- bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height);
+ bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode);
protected:
virtual bool can_process_result (SmartPtr<X3aResult> &result);
@@ -141,6 +141,7 @@
CLBlenderScaleMode _stitch_scale_mode;
uint32_t _stitch_width;
uint32_t _stitch_height;
+ uint32_t _stitch_res_mode;
};
};
diff --git a/modules/ocl/cv_feature_match.cpp b/modules/ocl/cv_feature_match.cpp
index b247270..5604f12 100644
--- a/modules/ocl/cv_feature_match.cpp
+++ b/modules/ocl/cv_feature_match.cpp
@@ -23,8 +23,34 @@
namespace XCam {
-#define XCAM_OF_DEBUG 0
-#define XCAM_OF_DRAW_SCALE 2
+#define XCAM_CV_FM_DEBUG 0
+#define XCAM_CV_OF_DRAW_SCALE 2
+
+#if XCAM_CV_FM_DEBUG
+static XCamReturn
+dump_buffer (SmartPtr<DrmBoBuffer> buffer, char *dump_name)
+{
+ ImageFileHandle file;
+
+ XCamReturn ret = file.open (dump_name, "wb");
+ if (ret != XCAM_RETURN_NO_ERROR) {
+ XCAM_LOG_ERROR ("open %s failed", dump_name);
+ return ret;
+ }
+
+ ret = file.write_buf (buffer);
+ if (ret != XCAM_RETURN_NO_ERROR) {
+ XCAM_LOG_ERROR ("write buffer to %s failed", dump_name);
+ file.close ();
+ return ret;
+ }
+
+ file.close ();
+ XCAM_LOG_INFO ("write buffer to %s done", dump_name);
+
+ return XCAM_RETURN_NO_ERROR;
+}
+#endif
CVFeatureMatch::CVFeatureMatch (SmartPtr<CLContext> &context)
: _context (context)
@@ -37,6 +63,12 @@
}
void
+CVFeatureMatch::set_config (const CVFMConfig config)
+{
+ _config = config;
+}
+
+void
CVFeatureMatch::init_opencv_ocl ()
{
if (_is_ocl_inited)
@@ -64,6 +96,31 @@
}
bool
+CVFeatureMatch::convert_to_mat (SmartPtr<CLContext> context, SmartPtr<DrmBoBuffer> buffer, cv::Mat &image)
+{
+ SmartPtr<CLBuffer> cl_buffer = new CLVaBuffer (context, buffer);
+ VideoBufferInfo info = buffer->get_video_info ();
+ cl_mem cl_mem_id = cl_buffer->get_mem_id ();
+
+ cv::UMat umat;
+ cv::ocl::convertFromBuffer (cl_mem_id, info.strides[0], info.height * 3 / 2, info.width, CV_8U, umat);
+ if (umat.empty ()) {
+ XCAM_LOG_ERROR ("convert bo buffer to UMat failed");
+ return false;
+ }
+
+ cv::Mat mat;
+ umat.copyTo (mat);
+ if (mat.empty ()) {
+ XCAM_LOG_ERROR ("copy UMat to Mat failed");
+ return false;
+ }
+
+ cv::cvtColor (mat, image, cv::COLOR_YUV2BGR_NV12);
+ return true;
+}
+
+bool
CVFeatureMatch::get_crop_image (
SmartPtr<DrmBoBuffer> buffer,
cv::Rect img_crop_left, cv::Rect img_crop_right,
@@ -108,9 +165,9 @@
count = 0;
sum = 0.0f;
for (uint32_t i = 0; i < status.size (); ++i) {
-#if XCAM_OF_DEBUG
- cv::Point start = cv::Point(corner0[i]) * XCAM_OF_DRAW_SCALE;
- cv::circle (image, start, 4, cv::Scalar(255, 255, 255), XCAM_OF_DRAW_SCALE);
+#if XCAM_CV_FM_DEBUG
+ cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE;
+ cv::circle (image, start, 4, cv::Scalar(255, 255, 255), XCAM_CV_OF_DRAW_SCALE);
#endif
if (!status[i] || error[i] > 24)
@@ -123,9 +180,9 @@
++count;
offsets.push_back (offset);
-#if XCAM_OF_DEBUG
- cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_OF_DRAW_SCALE;
- cv::line (image, start, end, cv::Scalar(255, 255, 255), XCAM_OF_DRAW_SCALE);
+#if XCAM_CV_FM_DEBUG
+ cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+ cv::line (image, start, end, cv::Scalar(255, 255, 255), XCAM_CV_OF_DRAW_SCALE);
#else
XCAM_UNUSED (image);
XCAM_UNUSED (img0_size);
@@ -141,7 +198,7 @@
mean_offset = sum / count;
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
XCAM_LOG_INFO (
"X-axis mean offset:%.2f, pre_mean_offset:%.2f (%d times, count:%d)",
mean_offset, 0.0f, 0, count);
@@ -167,7 +224,7 @@
}
mean_offset = sum / recur_count;
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
XCAM_LOG_INFO (
"X-axis mean offset:%.2f, pre_mean_offset:%.2f (%d times, count:%d)",
mean_offset, pre_mean_offset, try_times, recur_count);
@@ -201,7 +258,7 @@
cv::Size img1_size = image1.size ();
XCAM_ASSERT (img0_size.height == img1_size.height);
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
cv::Mat mat;
cv::UMat umat;
cv::Size size (img0_size.width + img1_size.width, img0_size.height);
@@ -222,7 +279,7 @@
mat.copyTo (out_image);
}
- cv::Size scale_size = size * XCAM_OF_DRAW_SCALE;
+ cv::Size scale_size = size * XCAM_CV_OF_DRAW_SCALE;
cv::resize (out_image, out_image, scale_size, 0, 0);
#endif
@@ -247,9 +304,9 @@
last_count = count;
last_mean_offset = mean_offset;
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
char file_name[1024];
- snprintf (file_name, 1023, "feature_match_%d_OF_%d.jpg", frame_num, idx);
+ snprintf (file_name, 1023, "fm_optical_flow_%d_%d.jpg", frame_num, idx);
cv::imwrite (file_name, out_image);
XCAM_LOG_INFO ("write feature match: %s", file_name);
#else
@@ -301,7 +358,7 @@
add_detected_data (img_left, fast_detector, corner_left);
if (corner_left.empty ()) {
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
if (idx == 1)
frame_num++;
idx = (idx == 0) ? 1 : 0;
@@ -316,7 +373,7 @@
status, err, valid_count, mean_offset, x_offset, frame_num, idx);
adjust_stitch_area (dst_width, x_offset, crop_left, crop_right);
-#if XCAM_OF_DEBUG
+#if XCAM_CV_FM_DEBUG
XCAM_LOG_INFO (
"Stiching area %d: left_area(x:%d, width:%d), right_area(x:%d, width:%d)",
idx, crop_left.x, crop_left.width, crop_right.x, crop_right.width);
@@ -362,6 +419,40 @@
_valid_count[0], _mean_offset[0], _x_offset[0], dst_width);
detect_and_match (img0_right, img1_left, img0_crop_right, img1_crop_left,
_valid_count[1], _mean_offset[1], _x_offset[1], dst_width);
+
+#if XCAM_CV_FM_DEBUG
+ static int frame = 0;
+ char file_name[1024];
+ VideoBufferInfo info = buf0->get_video_info ();
+
+ std::snprintf (file_name, 1023, "fm_in_%dx%d_%d_0.nv12", info.width, info.height, frame);
+ dump_buffer (buf0, file_name);
+ std::snprintf (file_name, 1023, "fm_in_%dx%d_%d_1.nv12", info.width, info.height, frame);
+ dump_buffer (buf1, file_name);
+
+ cv::Mat in_mat;
+ std::snprintf (file_name, 1023, "fm_in_stitch_area_%d_0.jpg", frame);
+ convert_to_mat (_context, buf0, in_mat);
+ cv::line (in_mat, cv::Point(img0_crop_left.x, 0), cv::Point(img0_crop_left.x, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img0_crop_left.x + img0_crop_left.width, 0),
+ cv::Point(img0_crop_left.x + img0_crop_left.width, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img0_crop_right.x, 0), cv::Point(img0_crop_right.x, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img0_crop_right.x + img0_crop_right.width, 0),
+ cv::Point(img0_crop_right.x + img0_crop_right.width, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::imwrite (file_name, in_mat);
+
+ std::snprintf (file_name, 1023, "fm_in_stitch_area_%d_1.jpg", frame);
+ convert_to_mat (_context, buf1, in_mat);
+ cv::line (in_mat, cv::Point(img1_crop_left.x, 0), cv::Point(img1_crop_left.x, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img1_crop_left.x + img1_crop_left.width, 0),
+ cv::Point(img1_crop_left.x + img1_crop_left.width, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img1_crop_right.x, 0), cv::Point(img1_crop_right.x, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::line (in_mat, cv::Point(img1_crop_right.x + img1_crop_right.width, 0),
+ cv::Point(img1_crop_right.x + img1_crop_right.width, dst_width), cv::Scalar(0, 0, 255), 2);
+ cv::imwrite (file_name, in_mat);
+
+ frame++;
+#endif
}
}
diff --git a/modules/ocl/cv_feature_match.h b/modules/ocl/cv_feature_match.h
index 68c1cc5..1c9645f 100644
--- a/modules/ocl/cv_feature_match.h
+++ b/modules/ocl/cv_feature_match.h
@@ -27,6 +27,7 @@
#include <dma_video_buffer.h>
#include <smartptr.h>
#include "xcam_obj_debug.h"
+#include "image_file_handle.h"
#include <cl_context.h>
#include <cl_device.h>
@@ -67,6 +68,8 @@
return _use_ocl;
}
+ void set_config (const CVFMConfig config);
+
void optical_flow_feature_match (
int output_width, SmartPtr<DrmBoBuffer> buf0, SmartPtr<DrmBoBuffer> buf1,
cv::Rect &img0_crop_left, cv::Rect &img0_crop_right, cv::Rect &img1_crop_left, cv::Rect &img1_crop_right);
@@ -74,6 +77,7 @@
protected:
void init_opencv_ocl ();
+ bool convert_to_mat (SmartPtr<CLContext> context, SmartPtr<DrmBoBuffer> buffer, cv::Mat &image);
bool get_crop_image (SmartPtr<DrmBoBuffer> buffer,
cv::Rect img_crop_left, cv::Rect img_crop_right, cv::UMat &img_left, cv::UMat &img_right);
diff --git a/tests/test-image-stitching.cpp b/tests/test-image-stitching.cpp
index 83736bf..512f2c4 100644
--- a/tests/test-image-stitching.cpp
+++ b/tests/test-image-stitching.cpp
@@ -30,42 +30,11 @@
#include "cl_fisheye_handler.h"
#include "cl_image_360_stitch.h"
-#define XCAM_STITCHING_DEBUG 0
+#define XCAM_TEST_STITCH_DEBUG 0
#define XCAM_ALIGNED_WIDTH 16
using namespace XCam;
-static CLStitchInfo
-get_stitch_initial_info ()
-{
- CLStitchInfo stitch_info;
-
- stitch_info.merge_width[0] = 56;
- stitch_info.merge_width[1] = 56;
-
- stitch_info.crop[0].left = 96;
- stitch_info.crop[0].right = 96;
- stitch_info.crop[0].top = 0;
- stitch_info.crop[0].bottom = 0;
- stitch_info.crop[1].left = 96;
- stitch_info.crop[1].right = 96;
- stitch_info.crop[1].top = 0;
- stitch_info.crop[1].bottom = 0;
-
- stitch_info.fisheye_info[0].center_x = 480.0f;
- stitch_info.fisheye_info[0].center_y = 480.0f;
- stitch_info.fisheye_info[0].wide_angle = 202.8f;
- stitch_info.fisheye_info[0].radius = 480.0f;
- stitch_info.fisheye_info[0].rotate_angle = -90.0f;
- stitch_info.fisheye_info[1].center_x = 1440.0f;
- stitch_info.fisheye_info[1].center_y = 480.0f;
- stitch_info.fisheye_info[1].wide_angle = 202.8f;
- stitch_info.fisheye_info[1].radius = 480.0f;
- stitch_info.fisheye_info[1].rotate_angle = 89.4f;
-
- return stitch_info;
-}
-
#if HAVE_OPENCV
void
init_opencv_ocl (SmartPtr<CLContext> context)
@@ -113,14 +82,16 @@
"\t--input-h optional, input height, default: 1080\n"
"\t--output-w optional, output width, default: 1920\n"
"\t--output-h optional, output width, default: 960\n"
- "\t--loop optional, how many loops need to run for performance test, default: 0\n"
- "\t--save optional, save file or not, select from [true/false], default: true\n"
+ "\t--res-mode optional, image resolution mode, select from [1080p/4k], default: 1080p\n"
"\t--scale-mode optional, image scaling mode, select from [local/global], default: local\n"
"\t--enable-seam optional, enable seam finder in blending area, default: no\n"
"\t--enable-fisheyemap optional, enable fisheye map, default: no\n"
#if HAVE_OPENCV
"\t--fm-ocl optional, enable ocl for feature match, select from [true/false], default: false\n"
#endif
+ "\t--save optional, save file or not, select from [true/false], default: true\n"
+ "\t--framerate optional, framerate of saved video, default: 30.0\n"
+ "\t--loop optional, how many loops need to run for performance test, default: 1\n"
"\t--help usage\n",
arg0);
}
@@ -168,11 +139,15 @@
int loop = 1;
bool enable_seam = false;
bool enable_fisheye_map = false;
+ CLBlenderScaleMode scale_mode = CLBlenderScaleLocal;
+ CLStitchResMode res_mode = CLStitchRes1080P;
+
#if HAVE_OPENCV
bool fm_ocl = false;
#endif
bool need_save_output = true;
- CLBlenderScaleMode scale_mode = CLBlenderScaleLocal;
+ double framerate = 30.0;
+
const char *file_in_name = NULL;
const char *file_out_name = NULL;
@@ -183,14 +158,16 @@
{"input-h", required_argument, NULL, 'h'},
{"output-w", required_argument, NULL, 'W'},
{"output-h", required_argument, NULL, 'H'},
- {"loop", required_argument, NULL, 'l'},
- {"save", required_argument, NULL, 's'},
+ {"res-mode", required_argument, NULL, 'R'},
{"scale-mode", required_argument, NULL, 'c'},
{"enable-seam", no_argument, NULL, 'S'},
{"enable-fisheyemap", no_argument, NULL, 'F'},
#if HAVE_OPENCV
{"fm-ocl", required_argument, NULL, 'O'},
#endif
+ {"save", required_argument, NULL, 's'},
+ {"framerate", required_argument, NULL, 'f'},
+ {"loop", required_argument, NULL, 'l'},
{"help", no_argument, NULL, 'e'},
{NULL, 0, NULL, 0},
};
@@ -218,11 +195,15 @@
case 'H':
output_height = atoi(optarg);
break;
- case 'l':
- loop = atoi(optarg);
- break;
- case 's':
- need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+ case 'R':
+ if (!strcasecmp (optarg, "1080p"))
+ res_mode = CLStitchRes1080P;
+ else if (!strcasecmp (optarg, "4k"))
+ res_mode = CLStitchRes4K;
+ else {
+ XCAM_LOG_ERROR ("incorrect resolution mode");
+ return -1;
+ }
break;
case 'c':
if (!strcasecmp (optarg, "local"))
@@ -245,6 +226,15 @@
fm_ocl = (strcasecmp (optarg, "true") == 0 ? true : false);
break;
#endif
+ case 's':
+ need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+ break;
+ case 'f':
+ framerate = atof(optarg);
+ break;
+ case 'l':
+ loop = atoi(optarg);
+ break;
case 'e':
usage (argv[0]);
return -1;
@@ -273,6 +263,13 @@
return -1;
}
+#if !HAVE_OPENCV
+ if (need_save_output) {
+ XCAM_LOG_WARNING ("non-OpenCV mode, can't save video");
+ need_save_output = false;
+ }
+#endif
+
printf ("Description------------------------\n");
printf ("input file:\t\t%s\n", file_in_name);
printf ("output file:\t\t%s\n", file_out_name);
@@ -280,24 +277,24 @@
printf ("input height:\t\t%d\n", input_height);
printf ("output width:\t\t%d\n", output_width);
printf ("output height:\t\t%d\n", output_height);
- printf ("loop count:\t\t%d\n", loop);
- printf ("save file:\t\t%s\n", need_save_output ? "true" : "false");
+ printf ("resolution mode:\t%s\n", res_mode == CLStitchRes1080P ? "1080P" : "4K");
printf ("scale mode:\t\t%s\n", scale_mode == CLBlenderScaleLocal ? "local" : "global");
printf ("seam mask:\t\t%s\n", enable_seam ? "true" : "false");
printf ("fisheye map:\t\t%s\n", enable_fisheye_map ? "true" : "false");
#if HAVE_OPENCV
printf ("feature match ocl:\t%s\n", fm_ocl ? "true" : "false");
#endif
+ printf ("save file:\t\t%s\n", need_save_output ? "true" : "false");
+ printf ("framerate:\t\t%.3lf\n", framerate);
+ printf ("loop count:\t\t%d\n", loop);
printf ("-----------------------------------\n");
context = CLDevice::instance ()->get_context ();
image_360 =
- create_image_360_stitch (
- context, enable_seam, scale_mode, enable_fisheye_map).dynamic_cast_ptr<CLImage360Stitch> ();
+ create_image_360_stitch (context, enable_seam,
+ scale_mode, enable_fisheye_map, res_mode).dynamic_cast_ptr<CLImage360Stitch> ();
XCAM_ASSERT (image_360.ptr ());
image_360->set_output_size (output_width, output_height);
- CLStitchInfo stitch_info = get_stitch_initial_info ();
- image_360->init_stitch_info (stitch_info);
#if HAVE_OPENCV
image_360->set_feature_match_ocl (fm_ocl);
#endif
@@ -323,7 +320,7 @@
cv::VideoWriter writer;
if (need_save_output) {
cv::Size dst_size = cv::Size (output_width, output_height);
- if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), 30, dst_size)) {
+ if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) {
XCAM_LOG_ERROR ("open file %s failed", file_out_name);
return -1;
}
@@ -350,15 +347,36 @@
ret = image_360->execute (input_buf, output_buf);
CHECK (ret, "image_360 stitch execute failed");
- if (need_save_output) {
#if HAVE_OPENCV
+ if (need_save_output) {
cv::Mat out_mat;
convert_to_mat (context, output_buf, out_mat);
- writer.write (out_mat);
+#if XCAM_TEST_STITCH_DEBUG
+ static int frame = 0;
+ char file_name [1024];
+ std::snprintf (file_name, 1023, "orig_fisheye_%d.jpg", frame);
+
+ cv::Mat in_mat;
+ convert_to_mat (context, input_buf, in_mat);
+ cv::circle (in_mat, cv::Point(stitch_info.fisheye_info[0].center_x, stitch_info.fisheye_info[0].center_y),
+ stitch_info.fisheye_info[0].radius, cv::Scalar(0, 0, 255), 2);
+ cv::circle (in_mat, cv::Point(stitch_info.fisheye_info[1].center_x, stitch_info.fisheye_info[1].center_y),
+ stitch_info.fisheye_info[1].radius, cv::Scalar(0, 255, 0), 2);
+ cv::imwrite (file_name, in_mat);
+
+ char frame_str[1024];
+ std::snprintf (frame_str, 1023, "%d", frame);
+ cv::putText (out_mat, frame_str, cv::Point(120, 120), cv::FONT_HERSHEY_COMPLEX, 2.0,
+ cv::Scalar(0, 0, 255), 2, 8, false);
+ std::snprintf (file_name, 1023, "stitched_img_%d.jpg", frame);
+ cv::imwrite (file_name, out_mat);
+
+ frame++;
#endif
- } else {
+ writer.write (out_mat);
+ } else
+#endif
ensure_gpu_buffer_done (output_buf);
- }
FPS_CALCULATION (image_stitching, XCAM_OBJ_DUR_FRAME_NUM);
++i;
diff --git a/wrapper/gstreamer/gstxcamfilter.cpp b/wrapper/gstreamer/gstxcamfilter.cpp
index 0e686d3..fdbef97 100644
--- a/wrapper/gstreamer/gstxcamfilter.cpp
+++ b/wrapper/gstreamer/gstxcamfilter.cpp
@@ -42,6 +42,7 @@
#define DEFAULT_PROP_STITCH_SCALE_MODE CLBlenderScaleLocal
#define DEFAULT_PROP_STITCH_FISHEYE_MAP FALSE
#define DEFAULT_PROP_STITCH_FM_OCL FALSE
+#define DEFAULT_PROP_STITCH_RES_MODE StitchRes1080P
XCAM_BEGIN_DECLARE
@@ -58,7 +59,8 @@
PROP_STITCH_ENABLE_SEAM,
PROP_STITCH_SCALE_MODE,
PROP_STITCH_FISHEYE_MAP,
- PROP_STITCH_FM_OCL
+ PROP_STITCH_FM_OCL,
+ PROP_STITCH_RES_MODE
};
#define GST_TYPE_XCAM_FILTER_COPY_MODE (gst_xcam_filter_copy_mode_get_type ())
@@ -168,6 +170,26 @@
return g_type;
}
+#define GST_TYPE_XCAM_FILTER_STITCH_RES_MODE (gst_xcam_filter_stitch_res_mode_get_type ())
+static GType
+gst_xcam_filter_stitch_res_mode_get_type (void)
+{
+ static GType g_type = 0;
+ static const GEnumValue stitch_res_mode_types [] = {
+ {StitchRes1080P, "Image stitch 1080P mode", "1080p"},
+ {StitchRes4K, "Image stitch 4K mode", "4k"},
+ {0, NULL, NULL}
+ };
+
+ if (g_once_init_enter (&g_type)) {
+ const GType type =
+ g_enum_register_static ("GstXCamFilterStitchResModeType", stitch_res_mode_types);
+ g_once_init_leave (&g_type, type);
+ }
+
+ return g_type;
+}
+
static GstStaticPadTemplate gst_xcam_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@@ -285,6 +307,12 @@
DEFAULT_PROP_STITCH_FM_OCL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
#endif
+ g_object_class_install_property (
+ gobject_class, PROP_STITCH_RES_MODE,
+ g_param_spec_enum ("stitch-res-mode", "stitch resolution mode", "Stitch Resolution Mode",
+ GST_TYPE_XCAM_FILTER_STITCH_RES_MODE, DEFAULT_PROP_STITCH_RES_MODE,
+ (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
gst_element_class_set_details_simple (element_class,
"Libxcam Filter",
"Filter/Effect/Video",
@@ -321,6 +349,7 @@
xcamfilter->stitch_fisheye_map = DEFAULT_PROP_STITCH_FISHEYE_MAP;
xcamfilter->stitch_fm_ocl = DEFAULT_PROP_STITCH_FM_OCL;
xcamfilter->stitch_scale_mode = DEFAULT_PROP_STITCH_SCALE_MODE;
+ xcamfilter->stitch_res_mode = DEFAULT_PROP_STITCH_RES_MODE;
xcamfilter->delay_buf_num = DEFAULT_DELAY_BUFFER_NUM;
xcamfilter->cached_buf_num = 0;
@@ -388,6 +417,9 @@
xcamfilter->stitch_fm_ocl = g_value_get_boolean (value);
break;
#endif
+ case PROP_STITCH_RES_MODE:
+ xcamfilter->stitch_res_mode = (StitchResMode) g_value_get_enum (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -438,6 +470,9 @@
g_value_set_boolean (value, xcamfilter->stitch_fm_ocl);
break;
#endif
+ case PROP_STITCH_RES_MODE:
+ g_value_set_enum (value, xcamfilter->stitch_res_mode);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -684,7 +719,7 @@
processor->set_image_stitch (
xcamfilter->enable_stitch, xcamfilter->stitch_enable_seam,
xcamfilter->stitch_scale_mode, xcamfilter->stitch_fisheye_map, xcamfilter->stitch_fm_ocl,
- GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info));
+ GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info), (uint32_t) xcamfilter->stitch_res_mode);
XCAM_LOG_INFO ("xcamfilter stitch output size width:%d height:%d",
GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info));
}
diff --git a/wrapper/gstreamer/gstxcamfilter.h b/wrapper/gstreamer/gstxcamfilter.h
index a41b22f..b7ccd5b 100644
--- a/wrapper/gstreamer/gstxcamfilter.h
+++ b/wrapper/gstreamer/gstxcamfilter.h
@@ -67,6 +67,11 @@
DENOISE_3D_UV
} Denoise3DModeType;
+enum StitchResMode {
+ StitchRes1080P = 0,
+ StitchRes4K
+};
+
typedef struct _GstXCamFilter GstXCamFilter;
typedef struct _GstXCamFilterClass GstXCamFilterClass;
@@ -87,6 +92,7 @@
gboolean stitch_fisheye_map;
gboolean stitch_fm_ocl;
CLBlenderScaleMode stitch_scale_mode;
+ StitchResMode stitch_res_mode;
uint32_t delay_buf_num;
uint32_t cached_buf_num;