2016-11-14 10 views
1

Я пытаюсь изменить изображение с помощью Qt с помощью метода scanLine(). Эти методы возвращают указатель на данные данной строки. Я основал, как читать строки here. Прямо сейчас, я могу прочитать значение всех пикселей, как это:Хранить все пиксели QImage с помощью метода scanLine() в C++

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; 
    } 
} 

Затем я обрабатываю каждый пиксель и попытаться добавить те, в новой переменной QRgb **, но это, где программа не во время выполнения.

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 


     } 
    } 

Я не понимаю, почему я не могу изменить ссылку на finalPixels[y][x] к новой ссылки. Является ли тип переменной неправильным? Или это не так? Я прочитал кое-что о двумерных массивах и указателях, но все же я не могу понять, в чем проблема.

EDIT

@rames ответил на этот вопрос, предложив использовать pixel() и setPixel() методы. Эти методы гораздо проще в использовании, но это не то, что я ищу. Моя первая реализация использует эти методы, но как setPixel() method's documentation говорит:

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.

И поскольку моя цель состоит в том, чтобы применить фильтры к изображению, как размытие, обнаружение края, мне нужно работать, так вот почему я пытаюсь использование scanLine().


Я попытался изменить свой тип переменной. А потом просто изменить цвет пикселей, как это:

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; 
    } 
} 

Но даже это не удается, когда программа работает pixels[y][x] = cr; и я не понимаю, почему. Выход QtCreator равен he program has unexpectedly finished..


Ok, так что я знаю, как изменить пиксели изображения с scanLine() методом благодаря @ user3528438 и @Rames. Но все же я не могу найти способ получить все пиксели в переменной. Моя цель - иметь временную переменную, таким образом, я могу вычислить модификацию изображения с исходными пикселями. Вот это последнее, что я пробовал:

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; 
    } 
} 

Эта компиляция и работать хорошо, но все значения 0 .. Если сравнивать с первоначальными пикселей, это не так. Можете ли вы объяснить мне, почему мои значения не являются оригинальными, и все ли они установлены в 0 в моей переменной *pixelsCopy? А также, не слишком ли тяжело называть метод scanLine() для каждого пикселя? Я также попытался изменить *pixelsCopy к pixelsCopy, но я все еще получаю значения 0 ..

EDIT 2

Благодаря @ user3528438 и @Rames, я, наконец, нашел способ скопировать пикселей в новый переменная, но я получаю странные результаты. Я написал код, который копирует пиксели и повторно применяет их к изображению, и я не получаю одинакового изображения.

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(); 

    } 
} 

И это до и после: enter image description here

Похожа координатной ошибкой, но я проверил несколько раз и ничего не видел .. Если у вас есть быстрее и/или очиститель способ скопировать исходные пиксели, будет приятно посоветовать мне!

+0

'программа не работает' не так много для работы. Как вы можете сказать, что это провалилось? –

+0

То, как вы выделяете память, ужасно ошибочно. и решение использовать '**' тоже сомнительно. я предлагаю не использовать '**' в этом случае, если нет очень веских причин. – user3528438

+0

@DaleWilson Когда я запускаю приложение с QtCreator, это единственный результат, который я получаю. Я протестировал и заметил, что он здесь. –

ответ

0

Поскольку мой вопрос был слишком широк, я создал a topic on the Qt Forum и Chris Kawa ответил точно на мою проблему.

скопировать пиксели в другой переменной

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 

процесса каждый пиксель

Мы можем прочитать каждый пиксель приращением х и у.

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

Но это будет медленно, будет гораздо быстрее использовать указатели.

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

STD Стиль: Скопируйте пиксели в другую переменную

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

STD Стиль: Обработать каждый пиксель

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

В C++ 17 вы даже способный распараллеливать и легко его сортировать так:

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

Благодарим Криса Кава за помощь, весь код выше был дан ему на эту тему я создал на Qt Forum.

1

Do не использовать массив. Класс QImage предназначен для манипулирования пикселями, и вы действительно должны использовать его. Предполагая, что img переменная имеет тип QImage *:

QImage finalImage(*img); 
for (int y = 0; y < finalImage.height(); ++y) { 
    QRgb *line = reinterpret_cast<QRgb*>(finalImage.scanLine(y)); 
    for (int x = 0; x < finalImage.width(); ++x) { 
     QRgb pixelRgb = line[x]; 
     // Process pixelRgb 

     QColor final(/* some new value */); 
     line[x] = final.rgb(); 
    } 
} 
+0

нет, это то, что я использовал раньше, и он работал, но это слишком ** тяжело и медленный**. Как сказано в документации '' setPixel' (http://doc.qt.io/qt-4.8/qimage.html#setPixel): 'Эта функция дорога из-за вызова внутренней функции detach(), вызванной внутри; если производительность является проблемой, мы рекомендуем использовать scanLine() для прямого доступа к данным пикселов. ' –

+0

И нет метода' setPixelColor' –

+0

@KevinM 'setPixelColor' был введен в Qt 5.6. Вы явно не упомянули, что используете Qt 4.8. Что касается производительности, я постараюсь показать вам более быструю версию в следующем редактировании. – Rames