【问题标题】:OPEN CV image.at<Vec3b>(b,a) function error in while loop while running second timeOPEN CV image.at<Vec3b>(b,a) 第二次运行时while循环中的函数错误
【发布时间】:2015-10-27 23:40:36
【问题描述】:

我的代码使用 OPENCV 进行图像处理,我想随机创建一组白色点的特征。程序在运行内部 WHILE LOOP SECOND TIME 时导致 Assertion failed 错误。我已经对该程序进行了评论和测试,以找出问题所在。我发现 image.at(b,a) 部分代码存在问题。第二次运行失败。虽然它第一次运行得非常好。
如果我在内部 while 循环中使用常量值而不是变量 b,a 运行代码,或者使用 (j,j) 变量运行代码。我用 fout 打印了一些调试语句。我还附上了 .txt 文件输出以帮助您了解正在发生的事情。

从 TXT 文件开始输出

while 循环的开始

在while循环中

在while循环之外

[255, 255, 255]404 1173 while循环开始

在while循环中

TXT 文件输出结束

很奇怪。请帮我解决这个问题! 我正在粘贴我的代码:

int main() {
    int i = 0;
    int a;
    ofstream fout("test.txt");
    int b;
    int j = 0;
    cv::Mat img;
    cv::Scalar* scalar_low;
    cv::Scalar* scalar_up;
    cv::Mat newimg;
    cv::Mat img2;
    stringstream ss;
    string s;
    scalar_low = new cv::Scalar(0, 30, 60);
    scalar_up = new cv::Scalar(20, 150, 255);
    int imgwidth;
    int imgheight;
    srand(112);
    while (j <= 45)
    {
    s="imagedata\\test"+ to_string(j);    
    s+=".jpg";
    img=imread(s);    
    cvtColor(img, img2, CV_BGR2HSV, 0);
    inRange(img2, *scalar_low, *scalar_up, newimg);            
    s="imagedata\\result"+ to_string(j);
    s+=".jpg";
    imwrite(s, newimg);
    imgwidth = newimg.cols;
    imgheight = newimg.rows;
    i = 0;
    while (i <= 499)
    {
        a = 0;
        b = 0;
               fout << "start of while loop \n";

            while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
            {
                fout << "inside the while loop \n"
                a = rand() % imgwidth;
                b = rand() % imgheight;

            }
            fout << "outside the while loop \n"; 
            fout << a;
            fout << " ";
            fout << b;
            fout << " ";
            i++;

        }

        j++;
        fout << "\n";

    }


}

【问题讨论】:

  • 您到底想达到什么目的?做“imgwidth = newimg.cols; imgheight = newimg.rows;”你应该没事。还可以阅读一些 C++ 教程并了解为什么你不需要指针,新的,“->”在这里
  • 正如@Miki 所说,宽度应对应于列数,高度应对应于行数。也许您对 x/y 排序和矩阵访问感到困惑。查看stackoverflow.com/questions/25642532/… 以获得可能的解释。
  • 我尝试了您的建议,但代码仍然无法正常工作。我修改了我的问题并包含了打印到 .txt 文件中的调试语句。
  • 您到底想达到什么目的?幻数上的两个while循环不是最佳选择:D
  • @Miki 我正在尝试从过滤后的图像中构建一个随机特征点集,这些点是白色的。这需要我随机生成点并检查它们是否是白色的......

标签: c++ opencv


【解决方案1】:

我正在尝试从过滤后的图像中构建一个随机的特征点集,这些点是白色的。这需要我随机生成点并检查它们是否是白色的

您不需要在正确的图像范围内生成随机点,并检查原始图像中的像素是否为白色。

你可以:

  • 获取掩码中的所有白色像素,使用findNonZero
  • 随机洗牌这些点,std::random_shuffle
  • 保持第一N洗牌点

蒙面图片:

随机采样N掩码中的白点:

代码:

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

int main()
{
    Mat3b img = imread("path_to_image");

    Mat3b hsv;
    cvtColor(img, hsv, COLOR_BGR2HSV);

    Mat1b mask;
    inRange(hsv, Scalar(0, 30, 60), Scalar(20, 150, 255), mask);

    // Get all white points in mask
    vector<Point> pts;
    findNonZero(mask, pts);

    int N = 1000; // number of random points to keep
    N = min(N, int(pts.size())); // not more than the actual white pixels

    // Random shuffle of white points
    random_shuffle(pts.begin(), pts.end());

    // Random subset of N white points in mask
    vector<Point> my_random_points(pts.begin(), pts.begin() + N);

    // Create a black image
    Mat1b random_in_mask(mask.rows, mask.cols, uchar(0));

    // Set selected random points to white
    for (const Point& pt : my_random_points)
    {
        random_in_mask(pt) = uchar(255);
    }

    imshow("Mask", mask);
    imshow("Random in Mask", random_in_mask);

    waitKey();

    return 0;
}

【讨论】:

  • thnks fr ur sln.this 帮助了我。但我真的很想了解我这样做的方式有什么问题。我的图像宽度是(列数)1728 和我的图像高度(行数是)3072,但我的 image.at 像素访问在 image.at(404, 1173) 处中断,两者都在图像宽度和图像高度的范围内。它很奇怪,但是当我访问 image.at(1173 ,404) 时,它给了我结果。 (理想情况下,它应该为 image.at(1173 ,404) 和 image.at(404, 1173) 提供结果)......因为 1173 和 404 都在 1728 和 3072 的范围内。 .....你知道吗???
  • newimg 是一个 CV_8UC1,您需要使用newimg.at&lt;uchar&gt;(rows, cols) 访问它。您可以使用以下命令检查值是否为零:if(!newimg.at&lt;uchar&gt;(rows, cols)){...}
  • @AsimUnmesh 在这样的情况下,我们通过投票表示谢谢 :D 很高兴它有帮助
  • 我正在尝试投票,它说的是关于声誉和 15 分的问题............ :D..... :)
  • @AsimUnmesh 别担心,很高兴你能成功。我希望我的回答至少显示了获得结果的正确程序。
【解决方案2】:

编辑: InRange 将newimg 的类型设为ucharCV_8U,因此将条件更改为:

newimg.at<uchar>(a,b) == (uchar) 0

将解决问题。根据下面的 cmets 更新了我的答案。

根据thisrow是维度0,也就是宽度。在at&lt;&gt;(i,j) 中,i 沿维度 0 j 沿维度 1。您的图像可能是矩形的,因此您的第二对 rand()-s 结果导致错误的 a,b-s。

编辑:在你的代码中你有

while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgwidth;
     b = rand() % imgheight;
}

改成

while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgheight;
     b = rand() % imgwidth;
}

或者

while ((newimg.at<Vec3b>(a,b) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgwidth;
     b = rand() % imgheight;
}

我是说这应该有效,而不是它会。

编辑#2:解释

你有一张像这样的图片,例如:

-----------
|         |
|         |
|         |
|         |
|         |
|         |
-----------

但是 a 和 be with at(b,a) 使用顺序会创建一个不同的矩形,所以:

------------------
|         |      |
|         |   2  |
|     1   |      |
|---------|-------
|         |
|         |
-----------

您的第一对随机数已生成到 (1) 位置,而第二对不在图像上。您没有使用srand(time(NULL));,因此您的随机数在每次运行时都是相同的。

【讨论】:

  • 抱歉,我无法正确理解为什么第二对 rand() 会导致错误的 a、b。在尝试了上述建议后,我也编辑了这个问题,并且我已经包含了一个 .txt 文件的输出,我在其中打印了调试语句。也许这些可以帮助您更好地了解我的问题。
  • @AsimUnmesh 我已经更新了我的答案以在我的代码中包含所需的编辑。
  • @AsimUnmesh 我明白了,我查看了它,在 core.hpp 中,查看第 1259 行的评论(inRange 上方):@param dst output array of the same size as src and CV_8U type. 所以 newtype 不是 Vec3b,它是 0b00000000 或0b11111111,没有频道。
  • @AsimUnmesh 很抱歉编辑了我的评论。不过,索引边界可能仍然是个问题。
  • 所以我建议尝试newimg.at&lt;uchar&gt;(a,b) == (uchar) 0 进行比较。如果可行,我会更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多