OneBitImageView* add_edge(const T &src, unsigned int interval)
{
    OneBitImageData* data = new OneBitImageData(src.size(), src.origin());
    OneBitImageView* view = new OneBitImageView(*data);
    copy(src.vec_begin(),
              src.vec_end(),
              view->vec_begin());

    for (unsigned int y=interval; y<view->nrows()-interval; y++) {
        view->set(Point(0, y), 1);
        view->set(Point(view->ncols()-1, y), 1);
    }
    for (unsigned int x=interval; x<view->ncols()-interval; x++) {
        view->set(Point(x, 0), 1);
        view->set(Point(0, view->nrows()-1), 1);
    }
    return view;
}
OneBitImageView* border_removal(const T &src,
                                int win_dil, int win_avg, int win_med,
                                double threshold1_scale, double threshold1_gradient,
                                double threshold2_scale, double threshold2_gradient,
                                double scale_length,
                                int terminate_time1, int terminate_time2, int terminate_time3,
                                unsigned int interval2, unsigned int interval3)
{
    // image resize
    double scalar=sqrt(double(AREA_STANDARD)/(src.nrows()*src.ncols()));
    GreyScaleImageView* src_scale=static_cast<GreyScaleImageView*>(scale(src, scalar, 1));

    // paper estimation
    GreyScaleImageView* blur1=paper_estimation(*src_scale, SMOOTH, win_dil, win_avg, win_med);
    GreyScaleImageView* blur2=paper_estimation(*src_scale, DETAIL, win_dil, win_avg, win_med);

    // edge detection
    OneBitImageView* boundary=edge_detection(*blur1, *blur2,
                                threshold1_scale, threshold1_gradient,
                                threshold2_scale, threshold2_gradient,
                                scale_length);

    // boundary reconstruct
    OneBitImageView* mask_scale=boundary_reconstruct(*boundary,
                                terminate_time1, terminate_time2, terminate_time3,
                                interval2, interval3);

    // image resize back
    OneBitImageView* mask_temp=static_cast<OneBitImageView*>(scale(*mask_scale, 1.0/scalar, 1));
    OneBitImageData* data = new OneBitImageData(src.size(), src.origin());
    OneBitImageView* mask = new OneBitImageView(*data);
    for (unsigned int m=0; m<mask->nrows(); m++) {
        for (unsigned int n=0; n<mask->ncols(); n++) {
            mask->set(Point(n, m), mask_temp->get(Point(n, m)));
        }
    }

    delete src_scale->data();
    delete src_scale;
    delete blur1->data();
    delete blur1;
    delete blur2->data();
    delete blur2;
    delete boundary->data();
    delete boundary;
    delete mask_scale->data();
    delete mask_scale;
    delete mask_temp->data();
    delete mask_temp;
    return mask;

}