如何在不使用 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,就报错了
你混淆了 rows
和 cols
:
试试这个:
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 的观点——创建一个比库函数性能更好的函数的可能性很小。
我是 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,就报错了
你混淆了 rows
和 cols
:
试试这个:
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 的观点——创建一个比库函数性能更好的函数的可能性很小。