如何在不使用 OpenCV 中的函数的情况下自行对图像进行阈值处理

How to thresholding image by ourselves without using fucntion in OpenCV

我是 OpenCV 的新手,我想自己对图像进行阈值处理而不使用 opencv 中的 Threshold 函数,因为函数 threshold 对我来说花费的时间太长了。

这是我的代码:

Mat src = imread("D:\DataBox\7.jpg", 0);
for (int i = 0; i < src.cols; i++) {
    cout << i << endl;
    for (int j = 0; j < src.rows; j++) {
        if (src.at<uchar>(i, j) > 70) {
            src.at<uchar>(i, j) = 0;
            cout << j << endl;
        }
        else
            src.at<uchar>(i, j) = 255;
    }
}

但它仍然说:

"OpenCV Error: Assertion failed (dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && ((((sizeof(size_t)<<28)|0x8442211) >> ((DataType<_Tp>::depth) & ((1 << 3) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file C:\Program Files\opencv\build\include\opencv2/core/mat.inl.hpp, line 894"

我可以从0~719打印j(因为图片的尺寸是720*960),但是只要参数我想从1变成2,就报错了

你混淆了 rowscols:

试试这个:

Mat src = imread("path_to_image", IMREAD_GRAYSCALE);
for (int i = 0; i < src.rows; i++) 
{
    //cout << i << endl;
    for (int j = 0; j < src.cols; j++) 
    {
        if (src.at<uchar>(i, j) > 70) {
            src.at<uchar>(i, j) = 0;
            //cout << j << endl;
        }
        else
            src.at<uchar>(i, j) = 255;
    }
}

然而,这不太可能比 OpenCV 实现更好。您可以在处理原始指针时获得一点速度,在可能的情况下使用一些小技巧来处理连续数据:

#include <opencv2\opencv.hpp>
using namespace cv;

int main()
{
    Mat src = imread("D:\SO\img\nice.jpg", IMREAD_GRAYSCALE);

    int rows = src.rows;
    int cols = src.cols;
    if (src.isContinuous())
    {
        cols = rows * cols;
        rows = 1;
    }

    for (int i = 0; i < rows; i++)
    {
        uchar* pdata = src.ptr<uchar>(i);
        int base = i*cols;
        for (int j = 0; j < cols; j++)
        {
            if (pdata[base + j] > 70)
            {
                pdata[base + j] = 0;
            }
            else
            {
                pdata[base + j] = 255;
            }
        }
    }
    return 0;
}

实际上,在我的电脑上,我的版本比 OpenCV 版本快一点:

Time @HenryChen (ms):   2.83266
Time @Miki (ms):        1.09597
Time @OpenCV (ms):      2.10727

您可以使用以下代码在您的 PC 上进行测试,因为时间取决于许多因素,例如OpenCV 中启用的优化:

#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat1b src(720,960);
    randu(src, 0, 256);

    Mat1b src1 = src.clone();
    Mat1b src2 = src.clone();
    Mat1b src3 = src.clone();

    double tic1 = double(getTickCount());

    // Method @HenryChen (corrected)
    for (int i = 0; i < src1.rows; i++)
    {
        //cout << i << endl;
        for (int j = 0; j < src1.cols; j++)
        {
            if (src1.at<uchar>(i, j) > 70) {
                src1.at<uchar>(i, j) = 0;
                //cout << j << endl;
            }
            else
                src1.at<uchar>(i, j) = 255;
        }
    }

    double toc1 = (double(getTickCount()) - tic1) * 1000.0 / getTickFrequency();
    cout << "Time @HenryChen (ms): \t" << toc1 << endl;

    //-------------------------------------

    double tic2 = double(getTickCount());

    // Method @Miki
    int rows = src2.rows;
    int cols = src2.cols;
    if (src2.isContinuous())
    {
        cols = rows * cols;
        rows = 1;
    }

    for (int i = 0; i < rows; i++)
    {
        uchar* pdata = src2.ptr<uchar>(0);
        int base = i*cols;
        for (int j = 0; j < cols; j++)
        {
            pdata[base + j] = (pdata[base + j] > 70) ? uchar(0) : uchar(255);
        }
    }

    double toc2 = (double(getTickCount()) - tic2) * 1000.0 / getTickFrequency();
    cout << "Time @Miki (ms): \t" << toc2 << endl;

    //-------------------------------------

    double tic3 = double(getTickCount());

    // Method @OpenCV
    threshold(src3, src3, 70, 255, THRESH_BINARY_INV);

    double toc3 = (double(getTickCount()) - tic3) * 1000.0 / getTickFrequency();
    cout << "Time @OpenCV (ms): \t" << toc3 << endl;


    getchar();
    return 0;
}

改用test.at<uchar>(cv::Point(i, j))。直接访问 cv::Mat 时我总是迷路 - cv::Point 稍微清理一下。

无论如何,我同意 Miki 的观点——创建一个比库函数性能更好的函数的可能性很小。