在 C++ 中使用 scanLine() 方法存储所有 QImage 的像素 [英] Store all QImage's pixels with scanLine() method in C++

查看:79
本文介绍了在 C++ 中使用 scanLine() 方法存储所有 QImage 的像素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Qt 和 说:

<块引用>

警告:由于内部调用,此函数开销很大detach() 函数内调用;如果性能是一个问题,我们推荐使用scanLine()直接访问像素数据.

而且由于我的目标是将过滤器应用于图像,例如模糊、边缘检测,我需要性能,所以这就是我尝试使用 scanLine() 的原因.

<小时>

我试图改变我的变量类型.然后像这样简单地改变像素的颜色:

QRgb * pixel[img->height()];#pragma omp 并行for (int y = 0; y height();++y)像素 [y] = (QRgb*) img->scanLine();}for (int x = 0; x width();++x) {for (int y = 0; y height();++y) {QColor c(0,0,0);QRgb cr = c.rgb();像素[y][x] = cr;}}

但是当程序运行 pixels[y][x] = cr; 时,即使这是失败的,我也不明白为什么.QtCreator 的输出是他的程序意外完成了..

<小时>

好的,感谢@user3528438 和@Rames,我知道如何使用 scanLine() 方法修改图像的像素.但是我仍然找不到一种方法来获取变量中的所有像素.我的目标是有一个临时变量,这样,我可以用原始像素计算对图像的修改.这是我尝试的最后一件事:

QRgb * pixelCopy[img->height()][img->width()];QRgb * pColor;for (int y = 0; y height();++y) {for (int x = 0; x width();++x) {pColor = new QRgb((QRgb)img->scanLine(y)[x]);pixelCopy[y][x] = pColor;}}for (int x = 0; x width();++x) {for (int y = 0; y height();++y) {int color = qRed(*pixelsCopy[y][x]);//返回 0std::cout <<像素在" <<x<<", " <<y<<是" <<颜色<

这个编译和运行良好,但所有值都是 0.. 如果我与原始像素进行比较,情况并非如此.你能向我解释为什么我的值不是原来的一次而是在我的 *pixelsCopy 变量中全部设置为 0 吗?而且,为每个像素调用 scanLine() 方法是不是太繁重了?我也尝试将 *pixelsCopy 更改为 pixelsCopy,但我仍然得到 0 值..

编辑 2

感谢@user3528438 和@Rames,我终于找到了一种将像素复制 到一个新变量中的方法,但我得到了奇怪的结果.我编写了一个代码来复制像素并将它们重新应用于图像,但我没有得到相同的图像.

QRgb pixelCopy[img->height()][img->width()];for (int y = 0; y height();++y) {QRgb * line = reinterpret_cast(img->scanLine(y));for (int x = 0; x width();++x) {pixelCopy[y][x] = line[x];}}for (int x = 0; x width();++x) {for (int y = 0; y height();++y) {int r = qRed(pixelsCopy[y][x]);QColor final(r, r, r);img->scanLine(y)[x] = final.rgb();}}

这是之前和之后:

它看起来像是坐标错误,但我检查了多次,什么也没看到.如果你有一种更快和/或更干净的方法来复制原始像素,它会很高兴给我建议!

解决方案

由于我的问题有点过于宽泛,所以我创建了 Qt 论坛上的主题Chris Kawa 准确地回答了我的问题.

将像素复制到另一个变量中

int size = img->height() * img->width();QRgb* 数据 = 新的 QRgb[大小];//不要忘记在某处删除它memmove(data, img.bits(), img.height() * img.width() * sizeof(QRgb));//我们不需要复制每个像素,这很慢

处理每个像素

我们可以通过增加 x 和 y 来读取每个像素.

for (int y = 0; y height(); ++y) {for (int x = 0; x width();++x) {

但这会很慢,使用指针会快得多.

QRgb* ptr = 数据;QRgb* end = ptr + img.width() * img.height();for (; ptr < end; ++ptr)*ptr = qRgb(qRed(*ptr), qRed(*ptr), qRed(*ptr));

STD 样式:将像素复制到另一个变量中

//复制std::vector像素;pixel.resize(img.height() * img.width());memmove(pixels.data(), img.bits(), img.height() * img.width() * sizeof(QRgb));

STD 风格:处理每个像素

std::for_each(pixels.begin(), pixel.end(), [](QRgb& c) { c = qRgb(qRed(c), qRed(c), qRed(c)); });

在 c++17 中,您甚至可以像这样轻松地并行化和验证它:

std::for_each(std::execution::parallel_unsequenced_policy,pixel.begin(), pixel.end(), [](QRgb& c) { c = qRgb(qRed(c), qRed(c), qRed(c));});

<小时>

感谢 Chris Kawa 的帮助,以上所有代码都是他根据我在 Qt 论坛上创建的主题提供的.

I am trying to modify an image using Qt with the scanLine() method. This methods return a pointer to the data of a given row. I founded how to read rows here. Right now, I am able to read the value of all pixels like this:

QRgb ** pixels;

pixels = (QRgb **) (malloc(sizeof (QRgb*) * img->width() * img->height()));

#pragma omp parallel for
for (int y = 0; y < img->height(); ++y) {
    pixels[y] = (QRgb*) img->scanLine(y);
}

for (int x = 0; x < img->width(); ++x) {
    for (int y = 0; y < img->height(); ++y) {
        int color =  qRed(pixels[y][x]);
        std::cout << "Pixel at " << x << ", " << y << " is " << color << std::endl;
    }
}

Then, I process each pixel and try to add those in a new QRgb ** variable, but this is where the program fails while executing.

QRgb ** finalPixels;

finalPixels = (QRgb **) (malloc(sizeof (QRgb*) * img->width() * img->height()));

    for (int x = 0; x < img->width(); ++x) {
        for (int y = 0; y < img->height(); ++y) {

            // Process pixels[y][x]


            QColor final(/* some new value */);
            QRgb finalrgb = final.rgb();

            finalPixels[y][x] = finalrgb; // What I realy want to do - Make the program fail
            finalPixels[y][x] = &finalrgb; // Don't build : invalid conversion from ‘QRgb* {aka unsigned int*}’ to ‘QRgb {aka unsigned int}’
            finalPixels[y][x] = pixels[y][x]; // Make the program fail


        }
    }

I don't understand why I can't change the reference of finalPixels[y][x] to a new reference. Is the type of the variable incorrect ? Or this is not how to do ? I readed some stuff about 2 dimensional arrays and pointers but still I can't figure out what is the problem here.

EDIT

@rames answered to this question by proposing to use pixel() and setPixel() methods. These methods are much easier to use, but this is not what I'm looking for. My first implementation was using these methods but as the setPixel() method's documentation says:

Warning: This function is expensive due to the call of the internal detach() function called within; if performance is a concern, we recommend the use of scanLine() to access pixel data directly.

And since my goal is to apply filters to an image like blur, edge detection, I need performance, so this is why I'm trying to use scanLine().


I tried to change my variable type. And then simply change the pixels' color like this:

QRgb * pixels[img->height()];


#pragma omp parallel 
for (int y = 0; y < img->height(); ++y)
   pixels[y] = (QRgb*) img->scanLine();
}

for (int x = 0; x < img->width(); ++x) {
  for (int y = 0; y < img->height(); ++y) {
      QColor c(0,0,0);
      QRgb cr = c.rgb();
      pixels[y][x] = cr;
  }
}

But even this is failing when the program runs pixels[y][x] = cr; and I don't understand why. The output of QtCreator is he program has unexpectedly finished..


Ok so I know how to modify the pixels of an image with the scanLine() method thanks to @user3528438 and @Rames. But still I can't find a way to get all the pixels in a variable. My goal is to have a temp variable, this way, I can compute a modification on the image with original pixels. Here is the last thing I tried:

QRgb * pixelsCopy[img->height()][img->width()];
QRgb * pColor;

for (int y = 0; y < img->height(); ++y) {
    for (int x = 0; x < img->width(); ++x) {
        pColor = new QRgb( (QRgb)img->scanLine(y)[x] );

        pixelsCopy[y][x] = pColor;
    }
}

for (int x = 0; x < img->width(); ++x) {
    for (int y = 0; y < img->height(); ++y) {
        int color =  qRed(*pixelsCopy[y][x]); // Return 0
        std::cout << "Pixel at " << x << ", " << y << " is " << color << std::endl;
    }
} 

This compile and run well, but all values are 0.. If I compare to the original pixels, this is not the case. Can you explain to me why my values are not the original onces and are all set to 0 in my *pixelsCopy variable ? And also, isn't is too heavy to call scanLine() method for each pixel ? I also tried to change *pixelsCopy to pixelsCopy, but I still get 0 values..

EDIT 2

Thanks to @user3528438 and @Rames, I finally found a way to copy pixels into a new variable, but I am getting weird results. I wrote a code that copy the pixels and reapply those to the image and I am not getting the same image.

QRgb pixelsCopy[img->height()][img->width()];

for (int y = 0; y < img->height(); ++y) {
    QRgb * line = reinterpret_cast<QRgb *>(img->scanLine(y));
    for (int x = 0; x < img->width(); ++x) {
        pixelsCopy[y][x] = line[x];
    }
}

for (int x = 0; x < img->width(); ++x) {
    for (int y = 0; y < img->height(); ++y) {
        int r = qRed(pixelsCopy[y][x]);
        QColor final(r, r, r);
        img->scanLine(y)[x] = final.rgb();

    }
}

And this is the before and after:

It looks like a coordinate mistake but I checked multiple times and saw nothing.. If you have a faster and/or cleaner way to copy the original pixels, It will be nice to advice me !

解决方案

Since my question was a bit too wide, I created a topic on the Qt Forum and Chris Kawa answered precisely to my problem.

Copy the pixels into another variable

int size = img->height() * img->width();
QRgb* data = new QRgb[size]; //don't forget to delete it somewhere
memmove(data, img.bits(), img.height() * img.width() * sizeof(QRgb));
// We don't need to copy each pixel, that's slow

Process each pixel

We can read each pixel by incrementing x and y.

for (int y = 0; y < img->height(); ++y) {
   for (int x = 0; x < img->width(); ++x) {

But this is going to be slow, it will be much faster to use pointers.

QRgb* ptr = data;
QRgb* end = ptr + img.width() * img.height();
for (; ptr < end; ++ptr)
    *ptr = qRgb(qRed(*ptr), qRed(*ptr), qRed(*ptr));

STD Style : Copy the pixels into another variable

//copy
std::vector<QRgb> pixels;
pixels.resize(img.height() * img.width());
memmove(pixels.data(), img.bits(), img.height() * img.width() * sizeof(QRgb));

STD Style : Process each pixel

std::for_each(pixels.begin(), pixels.end(), [](QRgb& c) { c = qRgb(qRed(c), qRed(c), qRed(c)); });

In c++17 you'll even be able to parallelize and vertorize it easily like this:

std::for_each(std::execution::parallel_unsequenced_policy, 
              pixels.begin(), pixels.end(), [](QRgb& c) { c = qRgb(qRed(c), qRed(c), qRed(c)); });


Thank Chris Kawa for the help, all the code above was given by him on the topic I created on the Qt Forum.

这篇关于在 C++ 中使用 scanLine() 方法存储所有 QImage 的像素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆