Home | History | Annotate | Download | only in soft
      1 /*
      2  * cv_capi_feature_match.cpp - optical flow feature match
      3  *
      4  *  Copyright (c) 2016-2017 Intel Corporation
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *   http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Wind Yuan <feng.yuan (at) intel.com>
     19  * Author: Yinhang Liu <yinhangx.liu (at) intel.com>
     20  * Author: Zong Wei <wei.zong (at) intel.com>
     21  */
     22 
     23 #include "cv_capi_feature_match.h"
     24 
     25 #define XCAM_CV_CAPI_FM_DEBUG 0
     26 
     27 #if XCAM_CV_CAPI_FM_DEBUG
     28 #include "ocl/cv_base_class.h"
     29 #endif
     30 
     31 namespace XCam {
     32 #if XCAM_CV_CAPI_FM_DEBUG
     33 static void
     34 debug_write_image (
     35     const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str);
     36 #endif
     37 
     38 CVCapiFeatureMatch::CVCapiFeatureMatch ()
     39     : FeatureMatch()
     40 {
     41 }
     42 
     43 bool
     44 CVCapiFeatureMatch::get_crop_image (
     45     const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, std::vector<char> &crop_image, CvMat &img)
     46 {
     47     VideoBufferInfo info = buffer->get_video_info ();
     48 
     49     uint8_t* image_buffer = buffer->map();
     50     int offset = info.strides[NV12PlaneYIdx] * crop_rect.pos_y + crop_rect.pos_x;
     51 
     52     crop_image.resize (crop_rect.width * crop_rect.height);
     53     for (int i = 0; i < crop_rect.height; i++) {
     54         for (int j = 0; j < crop_rect.width; j++) {
     55             crop_image[i * crop_rect.width + j] =
     56                 image_buffer[offset + i * info.strides[NV12PlaneYIdx] + j];
     57         }
     58     }
     59 
     60     img = cvMat (crop_rect.height, crop_rect.width, CV_8UC1, (void*)&crop_image[0]);
     61 
     62     return true;
     63 }
     64 
     65 void
     66 CVCapiFeatureMatch::add_detected_data (
     67     CvArr* image, std::vector<CvPoint2D32f> &corners)
     68 {
     69     std::vector<CvPoint2D32f> keypoints;
     70 
     71     int found_num = 300;
     72     double quality = 0.01;
     73     double min_dist = 5;
     74 
     75     corners.resize (found_num);
     76     CvPoint2D32f* corner_points = &corners[0];
     77 
     78     cvGoodFeaturesToTrack (image, NULL, NULL, corner_points, &found_num, quality, min_dist);
     79     XCAM_ASSERT (found_num <= 300);
     80 
     81 #if XCAM_CV_CAPI_FM_DEBUG
     82     XCAM_LOG_INFO ("FeatureMatch(idx:%d): detected corners:%d, reserved size:%d", _fm_idx, found_num, (int)corners.size ());
     83 #endif
     84     if (found_num < (int)corners.size ())
     85         corners.resize (found_num);
     86 }
     87 
     88 void
     89 CVCapiFeatureMatch::get_valid_offsets (
     90     std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
     91     std::vector<char> &status, std::vector<float> &error,
     92     std::vector<float> &offsets, float &sum, int &count,
     93     CvArr* image, CvSize &img0_size)
     94 {
     95     count = 0;
     96     sum = 0.0f;
     97 
     98     for (uint32_t i = 0; i < status.size (); ++i) {
     99         if (!status[i])
    100             continue;
    101 
    102 #if XCAM_CV_CAPI_FM_DEBUG
    103         cv::Mat mat = cv::cvarrToMat (image);
    104         cv::Point start = cv::Point (corner0[i].x, corner0[i].y);
    105         cv::circle (mat, start, 2, cv::Scalar(255), 2);
    106 #endif
    107         if (error[i] > _config.max_track_error)
    108             continue;
    109         if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y)
    110             continue;
    111         if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width)
    112             continue;
    113 
    114         float offset = corner1[i].x - corner0[i].x;
    115         sum += offset;
    116         ++count;
    117         offsets.push_back (offset);
    118 
    119 #if XCAM_CV_CAPI_FM_DEBUG
    120         cv::line (mat, start, cv::Point(corner1[i].x + img0_size.width, corner1[i].y), cv::Scalar(255), 2);
    121 #else
    122         XCAM_UNUSED (image);
    123         XCAM_UNUSED (img0_size);
    124 #endif
    125     }
    126 }
    127 
    128 void
    129 CVCapiFeatureMatch::calc_of_match (
    130     CvArr* image0, CvArr* image1,
    131     std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
    132     std::vector<char> &status, std::vector<float> &error,
    133     int &last_count, float &last_mean_offset, float &out_x_offset)
    134 {
    135     CvMat debug_image;
    136     CvSize img0_size = cvSize(((CvMat*)image0)->width, ((CvMat*)image0)->height);
    137     XCAM_ASSERT (img0_size.height == ((CvMat*)image1)->height);
    138     XCAM_UNUSED (image1);
    139 
    140     std::vector<float> offsets;
    141     float offset_sum = 0.0f;
    142     int count = 0;
    143     float mean_offset = 0.0f;
    144     offsets.reserve (corner0.size ());
    145 
    146 #if XCAM_CV_CAPI_FM_DEBUG
    147     CvSize img1_size = cvSize(((CvMat*)image1)->width, ((CvMat*)image1)->height);
    148     cv::Mat mat;
    149     mat.create (img0_size.height, img0_size.width + img1_size.width, ((CvMat*)image0)->type);
    150     debug_image = cvMat (img0_size.height, img0_size.width + img1_size.width, ((CvMat*)image0)->type, mat.ptr());
    151     cv::cvarrToMat(image0, true).copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height)));
    152     cv::cvarrToMat(image1, true).copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height)));
    153 #endif
    154 
    155     get_valid_offsets (corner0, corner1, status, error,
    156                        offsets, offset_sum, count, &debug_image, img0_size);
    157 
    158 #if XCAM_CV_CAPI_FM_DEBUG
    159     XCAM_LOG_INFO ("FeatureMatch(idx:%d): valid offsets:%d", _fm_idx, offsets.size ());
    160     char file_name[256] = {'\0'};
    161     std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx);
    162     cv::imwrite (file_name, mat);
    163 #endif
    164 
    165     bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset);
    166     if (ret) {
    167         if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) {
    168             out_x_offset = out_x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor);
    169 
    170             if (fabs (out_x_offset) > _config.max_adjusted_offset)
    171                 out_x_offset = (out_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
    172         }
    173     }
    174 
    175     last_count = count;
    176     last_mean_offset = mean_offset;
    177 }
    178 
    179 void
    180 CVCapiFeatureMatch::detect_and_match (
    181     CvArr* img_left, CvArr* img_right, Rect &crop_left, Rect &crop_right,
    182     int &valid_count, float &mean_offset, float &x_offset, int dst_width)
    183 {
    184     std::vector<float> err;
    185     std::vector<char> status;
    186     std::vector<CvPoint2D32f> corner_left, corner_right;
    187 
    188     CvSize win_size = cvSize (41, 41);
    189 
    190     add_detected_data (img_left, corner_left);
    191     int count = corner_left.size ();
    192     if (corner_left.empty ()) {
    193         return;
    194     }
    195 
    196     // find the corresponding points in img_right
    197     corner_right.resize (count);
    198     status.resize (count);
    199     err.resize (count);
    200 
    201     CvPoint2D32f* corner_points1 = &corner_left[0];
    202     CvPoint2D32f* corner_points2 = &corner_right[0];
    203     char* optflow_status = &status[0];
    204     float* optflow_errs = &err[0];
    205 
    206     cvCalcOpticalFlowPyrLK (
    207         img_left, img_right, 0, 0, corner_points1, corner_points2, count, win_size, 3,
    208         optflow_status, optflow_errs, cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 10, 0.01f), 0);
    209 
    210 #if XCAM_CV_CAPI_FM_DEBUG
    211     XCAM_LOG_INFO ("FeatureMatch(idx:%d): matched corners:%d", _fm_idx, count);
    212 #endif
    213 
    214     calc_of_match (img_left, img_right, corner_left, corner_right,
    215                    status, err, valid_count, mean_offset, x_offset);
    216 
    217     adjust_stitch_area (dst_width, x_offset, crop_left, crop_right);
    218 
    219 #if XCAM_CV_CAPI_FM_DEBUG
    220     XCAM_LOG_INFO (
    221         "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)",
    222         _fm_idx, crop_left.pos_x, crop_left.width, crop_right.pos_x, crop_right.width);
    223 #endif
    224 }
    225 
    226 void
    227 CVCapiFeatureMatch::optical_flow_feature_match (
    228     const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
    229     Rect &left_crop_rect, Rect &right_crop_rect, int dst_width)
    230 {
    231     CvMat left_img, right_img;
    232 
    233     if (!get_crop_image (left_buf, left_crop_rect, _left_crop_image, left_img)
    234             || !get_crop_image (right_buf, right_crop_rect, _right_crop_image, right_img))
    235         return;
    236 
    237     detect_and_match ((CvArr*)(&left_img), (CvArr*)(&right_img), left_crop_rect, right_crop_rect,
    238                       _valid_count, _mean_offset, _x_offset, dst_width);
    239 
    240 #if XCAM_CV_CAPI_FM_DEBUG
    241     XCAM_ASSERT (_fm_idx >= 0);
    242 
    243     char frame_str[64] = {'\0'};
    244     std::snprintf (frame_str, 64, "frame:%d", _frame_num);
    245     char fm_idx_str[64] = {'\0'};
    246     std::snprintf (fm_idx_str, 64, "fm_idx:%d", _fm_idx);
    247 
    248     char img_name[256] = {'\0'};
    249     std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", _frame_num, _fm_idx);
    250     debug_write_image (left_buf, left_crop_rect, img_name, frame_str, fm_idx_str);
    251 
    252     std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", _frame_num, _fm_idx);
    253     debug_write_image (right_buf, right_crop_rect, img_name, frame_str, fm_idx_str);
    254 
    255     XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", _fm_idx, _frame_num);
    256 
    257     _frame_num++;
    258 #endif
    259 }
    260 
    261 #if XCAM_CV_CAPI_FM_DEBUG
    262 static void
    263 debug_write_image (
    264     const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str)
    265 {
    266     cv::Scalar color = cv::Scalar(0, 0, 255);
    267     VideoBufferInfo info = buf->get_video_info ();
    268 
    269     cv::Mat mat;
    270     CVBaseClass cv_obj;
    271     cv_obj.convert_to_mat (buf, mat);
    272 
    273     cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
    274     cv::putText (mat, fm_idx_str, cv::Point(rect.pos_x, 70), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
    275 
    276     cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1);
    277     cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height),
    278               cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1);
    279 
    280     cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2);
    281     cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2);
    282 
    283     cv::imwrite (img_name, mat);
    284 }
    285 #endif
    286 
    287 }
    288