ronantakizawa/codereview-bench huggingface dataset:
Repository: opencv/opencv
File: modules/imgproc/test/test_subdivision2d.cpp (C++)

Code before:
    int trig_cnt = 0;
    for( std::vector<cv::Vec6f>::const_iterator it = triangles.begin(); it != triangles.end(); it++, trig_cnt++ )
    {
        EXPECT_TRUE( (0 <= triangles.at(trig_cnt).val[0] && triangles.at(trig_cnt).val[0] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[1] && triangles.at(trig_cnt).val[1] < 2000) &&
                     (0 <= triangles.at(trig_cnt).val[2] && triangles.at(trig_cnt).val[2] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[3] && triangles.at(trig_cnt).val[3] < 2000) &&
                     (0 <= triangles.at(trig_cnt).val[4] && triangles.at(trig_cnt).val[4] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[5] && triangles.at(trig_cnt).val[5] < 2000) );
    }
    EXPECT_EQ(trig_cnt, 105);
}

TEST(Imgproc_Subdiv2D, issue_25696) {
    std::vector<cv::Point2f> points{
        {0, 0}, {40, 40}, {84, 104}, {86, 108}
    };

    cv::Rect subdivRect{cv::Point{-10, -10}, cv::Point{96, 118}};
    cv::Subdiv2D subdiv{subdivRect};
    subdiv.insert(points);

    std::vector<cv::Vec6f> triangles;
    subdiv.getTriangleList(triangles);

    ASSERT_EQ(triangles.size(), 2);
}
}}


Review comment (suggestion):
CI Warning:
```
warning: comparison of integers of different signs: 'const unsigned long' and 'const int' [-Wsign-compare]
```

Also GTest macro signature says that expected value should go first.

Code after:
    int trig_cnt = 0;
    for( std::vector<cv::Vec6f>::const_iterator it = triangles.begin(); it != triangles.end(); it++, trig_cnt++ )
    {
        EXPECT_TRUE( (0 <= triangles.at(trig_cnt).val[0] && triangles.at(trig_cnt).val[0] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[1] && triangles.at(trig_cnt).val[1] < 2000) &&
                     (0 <= triangles.at(trig_cnt).val[2] && triangles.at(trig_cnt).val[2] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[3] && triangles.at(trig_cnt).val[3] < 2000) &&
                     (0 <= triangles.at(trig_cnt).val[4] && triangles.at(trig_cnt).val[4] < 1500) &&
                     (0 <= triangles.at(trig_cnt).val[5] && triangles.at(trig_cnt).val[5] < 2000) );
    }
    EXPECT_EQ(trig_cnt, 105);
}

TEST(Imgproc_Subdiv2D, issue_25696) {
    std::vector<cv::Point2f> points{
        {0, 0}, {40, 40}, {84, 104}, {86, 108}
    };

    cv::Rect subdivRect{cv::Point{-10, -10}, cv::Point{96, 118}};
    cv::Subdiv2D subdiv{subdivRect};
    subdiv.insert(points);

    std::vector<cv::Vec6f> triangles;
    subdiv.getTriangleList(triangles);

    ASSERT_EQ(static_cast<size_t>(2), triangles.size());
}
}}
Repository: opencv/opencv
File: modules/videoio/src/cap_ffmpeg_impl.hpp (C++)

Code before:
static CvVideoWriter_FFMPEG* cvCreateVideoWriterWithParams_FFMPEG( const char* filename, int fourcc, double fps,
                                                  int width, int height, const VideoWriterParameters& params )
{
    CvVideoWriter_FFMPEG* writer = new CvVideoWriter_FFMPEG();
    if (!writer)
        return 0;
    writer->init();
    if( writer->open( filename, fourcc, fps, width, height, params ))
        return writer;
    writer->close();
    delete writer;
    return 0;
}

CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
                                                  int width, int height, int isColor )
{
    VideoWriterParameters params;
    params.add(VIDEOWRITER_PROP_IS_COLOR, isColor);
    return cvCreateVideoWriterWithParams_FFMPEG(filename, fourcc, fps, width, height, params);
}

void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{
    if( writer && *writer )
    {
        (*writer)->close();
        delete *writer;
        *writer = 0;
    }
}


int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
                         const unsigned char* data, int step,
                         int width, int height, int type, int origin)
{
    return writer->writeFrame(data, step, width, height, type, origin);
}


Review comment (suggestion):
This is a part of external API (`cap_ffmpeg_legacy_api.hpp`), we can't just change parameters meaning.

Code after:
    writer->init();
    if( writer->open( filename, fourcc, fps, width, height, params ))
        return writer;
    writer->close();
    delete writer;
    return 0;
}

CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
                                                  int width, int height, int isColor )
{
    VideoWriterParameters params;
    params.add(VIDEOWRITER_PROP_IS_COLOR, isColor);
    return cvCreateVideoWriterWithParams_FFMPEG(filename, fourcc, fps, width, height, params);
}

void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
{
    if( writer && *writer )
    {
        (*writer)->close();
        delete *writer;
        *writer = 0;
    }
}


int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
                         const unsigned char* data, int step,
                         int width, int height, int cn, int origin)
{
    return writer->writeFrame(data, step, width, height, cn, origin);
}
Repository: opencv/opencv
File: modules/videoio/misc/java/src/cpp/videoio_converters.hpp (C++)

Code before:
#ifndef VIDEOIO_CONVERTERS_HPP
#define VIDEOIO_CONVERTERS_HPP

#include <jni.h>
#include "opencv_java.hpp"
#include "opencv2/core.hpp"
#include "opencv2/videoio/videoio.hpp"

class JavaStreamReader : public cv::IStreamReader
{
public:
    JavaStreamReader(JNIEnv* env, jobject obj);
    ~JavaStreamReader();
    long long read(char* buffer, long long size) CV_OVERRIDE;
    long long seek(long long offset, int way) CV_OVERRIDE;

private:
    JNIEnv* env;
    jobject obj;
    jmethodID m_read, m_seek;
};

jobject vector_VideoCaptureAPIs_to_List(JNIEnv* env, std::vector<cv::VideoCaptureAPIs>& vs);

#endif


Review comment (suggestion):
> The JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads. If a piece of code has no other way to get its JNIEnv, you should share the JavaVM, and use GetEnv to discover the thread's JNIEnv. (Assuming it has one; see AttachCurrentThread below.)

Source: https://developer.android.com/training/articles/perf-jni?hl=en

Looks like the adapter should handle the threading model in smarter way.

Code after:
#ifndef VIDEOIO_CONVERTERS_HPP
#define VIDEOIO_CONVERTERS_HPP

#include <jni.h>
#include "opencv_java.hpp"
#include "opencv2/core.hpp"
#include "opencv2/videoio/videoio.hpp"

class JavaStreamReader : public cv::IStreamReader
{
public:
    JavaStreamReader(JNIEnv* env, jobject obj);
    ~JavaStreamReader();
    long long read(char* buffer, long long size) CV_OVERRIDE;
    long long seek(long long offset, int way) CV_OVERRIDE;

private:
    JavaVM* vm;
    jobject obj;
    jmethodID m_read, m_seek;
};

jobject vector_VideoCaptureAPIs_to_List(JNIEnv* env, std::vector<cv::VideoCaptureAPIs>& vs);

#endif
Repository: opencv/opencv
File: modules/videoio/misc/java/src/cpp/videoio_converters.cpp (C++)

Code before:
    return res;
}

long long JavaStreamReader::seek(long long offset, int way)
{
    JNIEnv* env;
    if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
        return 0;
    if (!m_seek)
        return 0;
    return env->CallLongMethod(obj, m_seek, offset, way);
}

// Same as dnn::vector_Target_to_List
jobject vector_VideoCaptureAPIs_to_List(JNIEnv* env, std::vector<cv::VideoCaptureAPIs>& vs)
{
    static jclass juArrayList   = ARRAYLIST(env);
    static jmethodID m_create   = CONSTRUCTOR(env, juArrayList);
    jmethodID m_add       = LIST_ADD(env, juArrayList);

    static jclass jInteger = env->FindClass("java/lang/Integer");
    static jmethodID m_create_Integer = env->GetMethodID(jInteger, "<init>", "(I)V");

    jobject result = env->NewObject(juArrayList, m_create, vs.size());
    for (size_t i = 0; i < vs.size(); ++i)
    {
        jobject element = env->NewObject(jInteger, m_create_Integer, vs[i]);
        env->CallBooleanMethod(result, m_add, element);
        env->DeleteLocalRef(element);
    }
    return result;
}


Review comment (suggestion):
In general these callbacks are called from FFmpeg non-Java threads.

`JNIEnv` may be not available for native threads.

Should we use `AttachCurrentThread` in that case instead of `return 0` ?

Docs:

> For example, a thread started with pthread_create() or std::thread can be attached using the AttachCurrentThread() or AttachCurrentThreadAsDaemon() functions. Until a thread is attached, it has no JNIEnv, and cannot make JNI calls.

But there is dedicated issue with detaching of such threads.

Code after:
JavaStreamReader::JavaStreamReader(JNIEnv* env, jobject _obj)
{
    obj = env->NewGlobalRef(_obj);
    jclass cls = env->GetObjectClass(obj);
    m_read = env->GetMethodID(cls, "read", "([BJ)J");
    m_seek = env->GetMethodID(cls, "seek", "(JI)J");
    env->GetJavaVM(&vm);
}

JavaStreamReader::~JavaStreamReader()
{
    JNIEnvHandler handler(vm);
    JNIEnv* env = handler.env;
    if (!env)
        return;
    env->DeleteGlobalRef(obj);
}

long long JavaStreamReader::read(char* buffer, long long size)
{
    if (!m_read)
        return 0;
    JNIEnvHandler handler(vm);
    JNIEnv* env = handler.env;
    if (!env)
        return 0;
    jbyteArray jBuffer = env->NewByteArray(static_cast<jsize>(size));
    if (!jBuffer)
        return 0;
    jlong res = env->CallLongMethod(obj, m_read, jBuffer, size);
    env->GetByteArrayRegion(jBuffer, 0, static_cast<jsize>(size), reinterpret_cast<jbyte*>(buffer));
    env->DeleteLocalRef(jBuffer);
    return res;
}

long long JavaStreamReader::seek(long long offset, int way)
{
    JNIEnvHandler handler(vm);
    JNIEnv* env = handler.env;
    if (!env)
        return 0;
    if (!m_seek)
        return 0;
    return env->CallLongMethod(obj, m_seek, offset, way);
}

// Same as dnn::vector_Target_to_List
jobject vector_VideoCaptureAPIs_to_List(JNIEnv* env, std::vector<cv::VideoCaptureAPIs>& vs)
{
    static jclass juArrayList   = ARRAYLIST(env);
    static jmethodID m_create   = CONSTRUCTOR(env, juArrayList);
Repository: opencv/opencv
File: modules/imgcodecs/src/grfmt_png.cpp (C++)

Code before:

    if( !m_buf.empty() )
        png_set_read_fn(m_png_ptr, this, (png_rw_ptr)readDataFromBuf );
    else
    {
        m_f = fopen(m_filename.c_str(), "rb");
        if (!m_f)
        {
            return false;
        }
        png_init_io(m_png_ptr, m_f);
    }

    // Read PNG header: 137 80 78 71 13 10 26 10
    if (!readFromStreamOrBuffer(&sig, 8))
        return false;

    // IHDR chunk shall be first. ( https://www.w3.org/TR/png-3/#5ChunkOrdering )
    id = read_chunk(m_chunkIHDR);
    if (id != id_IHDR)
    {
        CV_LOG_IF_ERROR(NULL, id == id_CgBI, "CgBI chunk(Apple private) shall not be first instead of IHDR");
        CV_LOG_IF_ERROR(NULL, id != id_CgBI, "IHDR chunk shall be first, this data may be broken");
        return false;
    }

    m_is_fcTL_loaded = false;
    while (true)
    {
        id = read_chunk(chunk);

        if (!id || (m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total()))
        {
            return false;
        }

        if (id == id_IDAT)
        {
            if (m_f)
                fseek(m_f, 0, SEEK_SET);
            else
                m_buf_pos = 0;
            break;
        }

        if (id == id_acTL)
        {
            // https://wiki.mozilla.org/APNG_Specification#%60acTL%60:_The_Animation_Control_Chunk
            m_animation.loop_count = png_get_uint_32(&chunk.p[12]);

            m_frame_count = png_get_uint_32(&chunk.p[8]);

Review comment (bug):
chatGPT suggests

```
if (id == id_CgBI)
{
    CV_LOG_ERROR(NULL, "CgBI chunk (Apple private) found as the first chunk. IHDR is expected.");
}
else
{
    CV_LOG_ERROR(NULL, "IHDR chunk shall be first. This data may be broken or malformed.");
}
```

Code after:

    if( !m_buf.empty() )
        png_set_read_fn(m_png_ptr, this, (png_rw_ptr)readDataFromBuf );
    else
    {
        m_f = fopen(m_filename.c_str(), "rb");
        if (!m_f)
        {
            return false;
        }
        png_init_io(m_png_ptr, m_f);
    }

    // Read PNG header: 137 80 78 71 13 10 26 10
    if (!readFromStreamOrBuffer(&sig, 8))
        return false;

    // IHDR chunk shall be first. ( https://www.w3.org/TR/png-3/#5ChunkOrdering )
    id = read_chunk(m_chunkIHDR);
    if (id == id_CgBI)
    {
        CV_LOG_ERROR(NULL, "CgBI chunk (Apple private) found as the first chunk. IHDR is expected.");
        return false;
    }
    if (id != id_IHDR)
    {
        CV_LOG_ERROR(NULL, "IHDR chunk shall be first. This data may be broken or malformed.");
        return false;
    }

    m_is_fcTL_loaded = false;
    while (true)
    {
        id = read_chunk(chunk);

        if (!id || (m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total()))
        {
            return false;
        }

        if (id == id_IDAT)
        {
            if (m_f)
                fseek(m_f, 0, SEEK_SET);
            else
                m_buf_pos = 0;
            break;
        }

        if (id == id_acTL)
        {
Repository: opencv/opencv
File: samples/dnn/deblurring.cpp (C++)

Code before:
    }

    Net net = readNetFromONNX(modelPath, engine);
    net.setPreferableBackend(getBackendID(backend));
    net.setPreferableTarget(getTargetID(target));

    Mat inputImage = imread(findFile(imgPath));
    if (inputImage.empty()) {
        cerr << "Error: Input image could not be loaded." << endl;
        return -1;
    }
    Mat image = inputImage.clone();

    Mat image_blob = blobFromImage(image, scale, Size(image.cols, image.rows), mean_v, swapRB, false);

    net.setInput(image_blob);
    Mat output = net.forward();

    // Post Processing
    Mat output_transposed(3, &output.size[1], CV_32F, output.ptr<float>());

    vector<Mat> channels;
    for (int i = 0; i < 3; ++i) {
        channels.push_back(Mat(output_transposed.size[1], output_transposed.size[2], CV_32F,
                                    output_transposed.ptr<float>(i)));
    }
    Mat outputImage;
    merge(channels, outputImage);
    outputImage.convertTo(outputImage, CV_8UC3, 255.0);
    cvtColor(outputImage, outputImage, COLOR_RGB2BGR);

    imshow("Input Image", inputImage);
    imshow("Output Image", outputImage);
    waitKey(0);
    return 0;
}


Review comment (suggestion):
```
vector<Mat> channels = {
    Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(0)),
    Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(1)),
    Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(2))
};
```

Code after:
    }

    Net net = readNetFromONNX(modelPath, engine);
    net.setPreferableBackend(getBackendID(backend));
    net.setPreferableTarget(getTargetID(target));

    Mat inputImage = imread(findFile(imgPath));
    if (inputImage.empty()) {
        cerr << "Error: Input image could not be loaded." << endl;
        return -1;
    }
    Mat image = inputImage.clone();

    Mat image_blob = blobFromImage(image, scale, Size(image.cols, image.rows), mean_v, swapRB, false);

    net.setInput(image_blob);
    Mat output = net.forward();

    // Post Processing
    Mat output_transposed(3, &output.size[1], CV_32F, output.ptr<float>());

    vector<Mat> channels = {
        Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(2)),
        Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(1)),
        Mat(output_transposed.size[1], output_transposed.size[2], CV_32F, output_transposed.ptr<float>(0))
    };

    Mat outputImage;
    merge(channels, outputImage);
    outputImage.convertTo(outputImage, CV_8UC3, 255.0);

    imshow("Input Image", inputImage);
    imshow("Output Image", outputImage);
    waitKey(0);
    return 0;
}
Repository: opencv/opencv
File: modules/core/test/test_mat.cpp (C++)

Code before:

TEST(Core_Mat, regression_9507)
{
    cv::Mat m = Mat::zeros(5, 5, CV_8UC3);
    cv::Mat m2{m};
    EXPECT_EQ(25u, m2.total());
}

TEST(Core_Mat, empty)
{
    // Should not crash.
    uint8_t data[2] = {0, 1};
    cv::Mat mat_nd(/*ndims=*/0, /*sizes=*/nullptr, CV_8UC1, /*data=*/data);
    cv::Mat1b mat(0, 0, /*data=*/data, /*steps=*/1);
}

TEST(Core_InputArray, empty)
{
    vector<vector<Point> > data;
    ASSERT_TRUE( _InputArray(data).empty() );
}

TEST(Core_CopyMask, bug1918)
{
    Mat_<unsigned char> tmpSrc(100,100);
    tmpSrc = 124;
    Mat_<unsigned char> tmpMask(100,100);
    tmpMask = 255;
    Mat_<unsigned char> tmpDst(100,100);
    tmpDst = 2;
    tmpSrc.copyTo(tmpDst,tmpMask);
    ASSERT_EQ(sum(tmpDst)[0], 124*100*100);
}

TEST(Core_SVD, orthogonality)
{
    for( int i = 0; i < 2; i++ )
    {
        int type = i == 0 ? CV_32F : CV_64F;
        Mat mat_D(2, 2, type);
        mat_D.setTo(88.);
        Mat mat_U, mat_W;
        SVD::compute(mat_D, mat_W, mat_U, noArray(), SVD::FULL_UV);
        mat_U *= mat_U.t();
        ASSERT_LT(cvtest::norm(mat_U, Mat::eye(2, 2, type), NORM_INF), 1e-5);
    }
}


TEST(Core_SparseMat, footprint)
{

Review comment (bug):
suggest to add some checks to the test:

```
TEST(Core_Mat, empty)
{
    // Should not crash.
    uint8_t data[2] = {0, 1};
    cv::Mat mat_nd(/*ndims=*/0, /*sizes=*/nullptr, CV_8UC1, /*data=*/data);
    cv::Mat1b mat(0, 0, /*data=*/data, /*steps=*/1);
    EXPECT_EQ(mat_nd.dims, 0);
    EXPECT_EQ(mat.dims, 2);
    EXPECT_LE(mat_nd.total(), 1u); // 0 for 4.x, 1 for 5.x
    EXPECT_EQ(mat.total(), 0u);
    EXPECT_TRUE(mat.empty());
    // mat_nd.empty() should return true for 4.x and false for 5.x
}
```


Code after:

TEST(Core_Mat, regression_9507)
{
    cv::Mat m = Mat::zeros(5, 5, CV_8UC3);
    cv::Mat m2{m};
    EXPECT_EQ(25u, m2.total());
}

TEST(Core_Mat, empty)
{
    // Should not crash.
    uint8_t data[2] = {0, 1};
    cv::Mat mat_nd(/*ndims=*/0, /*sizes=*/nullptr, CV_8UC1, /*data=*/data);
    cv::Mat1b mat(0, 0, /*data=*/data, /*steps=*/1);
    EXPECT_EQ(mat_nd.dims, 0);
    EXPECT_EQ(mat.dims, 2);
#if CV_VERSION_MAJOR < 5
    EXPECT_LE(mat_nd.total(), 0u);
    EXPECT_TRUE(mat_nd.empty());
#else
    EXPECT_LE(mat_nd.total(), 1u);
    EXPECT_FALSE(mat_nd.empty());
#endif
    EXPECT_EQ(mat.total(), 0u);
    EXPECT_TRUE(mat.empty());
}

TEST(Core_InputArray, empty)
{
    vector<vector<Point> > data;
    ASSERT_TRUE( _InputArray(data).empty() );
}

TEST(Core_CopyMask, bug1918)
{
    Mat_<unsigned char> tmpSrc(100,100);
    tmpSrc = 124;
    Mat_<unsigned char> tmpMask(100,100);
    tmpMask = 255;
    Mat_<unsigned char> tmpDst(100,100);
    tmpDst = 2;
    tmpSrc.copyTo(tmpDst,tmpMask);
    ASSERT_EQ(sum(tmpDst)[0], 124*100*100);
}

TEST(Core_SVD, orthogonality)
{
    for( int i = 0; i < 2; i++ )
    {
        int type = i == 0 ? CV_32F : CV_64F;
        Mat mat_D(2, 2, type);
Repository: opencv/opencv
File: modules/features2d/perf/perf_fast.cpp (C++)

Code before:
        testing::Values(20,30,100),                   // threshold
        testing::Values(
            // (int)FastFeatureDetector::TYPE_5_8,
            // (int)FastFeatureDetector::TYPE_7_12,
            (int)FastFeatureDetector::TYPE_9_16       // detector_type
        ),
        testing::Bool(),                              // nonmaxSuppression
        testing::Values("cv/inpaint/orig.png",
                        "cv/cameracalibration/chess9.png")
    ))
{
    int threshold_p = get<0>(GetParam());
    int type_p = get<1>(GetParam());
    bool nonmaxSuppression_p = get<2>(GetParam());
    string filename = getDataPath(get<3>(GetParam()));

    Mat img = imread(filename, IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty()) << "Failed to load image: " << filename;

    vector<KeyPoint> keypoints;

    int64 t1 = cv::getTickCount();
    for(int i = 0; i < 10; i++) {
        FAST(img, keypoints, threshold_p, nonmaxSuppression_p, (FastFeatureDetector::DetectorType)type_p);
    }
    int64 t2 = cv::getTickCount();
    declare.in(img);
    TEST_CYCLE()
    {
        FAST(img, keypoints, threshold_p, nonmaxSuppression_p, (FastFeatureDetector::DetectorType)type_p);
    }

    // SANITY_CHECK_KEYPOINTS(keypoints);
    SANITY_CHECK_NOTHING();
}

} // namespace opencv_test


Review comment (suggestion):
Warnings:

  Warning: /home/ci/opencv/modules/features2d/perf/perf_fast.cpp:34:11: warning: unused variable 't1' [-Wunused-variable]
  Warning: /home/ci/opencv/modules/features2d/perf/perf_fast.cpp:38:11: warning: unused variable 't2' [-Wunused-variable]

Code after:
        testing::Values(20,30,100),                   // threshold
        testing::Values(
            // (int)FastFeatureDetector::TYPE_5_8,
            // (int)FastFeatureDetector::TYPE_7_12,
            (int)FastFeatureDetector::TYPE_9_16       // detector_type
        ),
        testing::Bool(),                              // nonmaxSuppression
        testing::Values("cv/inpaint/orig.png",
                        "cv/cameracalibration/chess9.png")
    ))
{
    int threshold_p = get<0>(GetParam());
    int type_p = get<1>(GetParam());
    bool nonmaxSuppression_p = get<2>(GetParam());
    string filename = getDataPath(get<3>(GetParam()));

    Mat img = imread(filename, IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty()) << "Failed to load image: " << filename;

    vector<KeyPoint> keypoints;

    declare.in(img);
    TEST_CYCLE()
    {
        FAST(img, keypoints, threshold_p, nonmaxSuppression_p, (FastFeatureDetector::DetectorType)type_p);
    }

    SANITY_CHECK_NOTHING();
}

} // namespace opencv_test