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

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

问题描述

我正在尝试使用 Qt

这看起来像是座标错误,但我检查了多次却什么也没看到..如果您有更快和/或 cleaner 的方式来复制原始像素,会很好地建议我!

解决方案

由于我的问题有点太宽,我创建了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天全站免登陆