Russian Qt Forum

Qt => Общие вопросы => Тема начата: GPPsoft от Декабрь 14, 2013, 09:19



Название: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 09:19
Здравствуйте. Нужен аналог данного метода класса Bitmap в C#. Мне нужно получить указатель на начало указанного участка изображения. В C# я делал так:
Код
C#
Bitmap currentRegionMap = ....
 
BitmapData btmData= currentRegionMap.LockBits(new Rectangle(x, y, width, height), ImageLockMode.ReadOnly, currentRegionMap.PixelFormat);
 
byte* a = (byte*)btmData.Scan0.ToPointer();
 
 

Как сделать похожее в Qt? Заранее спасибо за ответы!


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 14, 2013, 09:26
QImage::bits()
QImage::scanLine(int i)


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 10:18
QImage::scanLine(int i)
Указатель на начало с пикселя i? Т.е нумерация пикселей построчная? Т.е к примеру если 2 строки по 200 пикселей, то 101 пиксель будет на начале второй строки :)?


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 14, 2013, 10:28
Указатель на начало с пикселя i?
Возвращает указатель на первый пиксель i-той строки.

Т.е к примеру если 2 строки по 200 пикселей, то 101 пиксель будет на начале второй строки :)?
Если i == 1, то вернется указатель на начало второй строки, на 200-тый пиксель в памяти. Нумерация с 0.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 11:32
Указатель на начало с пикселя i?
Возвращает указатель на первый пиксель i-той строки.

Т.е к примеру если 2 строки по 200 пикселей, то 101 пиксель будет на начале второй строки :)?
Если i == 1, то вернется указатель на начало второй строки, на 200-тый пиксель в памяти. Нумерация с 0.

Ок. Спасибо. Жаль нет аналогичной функции чтобы не высчитывать вручную.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 14, 2013, 11:39
Жаль нет аналогичной функции чтобы не высчитывать вручную.
Где нет?
И что там считать, все же элементарно. :)


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 11:53
Жаль нет аналогичной функции чтобы не высчитывать вручную.
Где нет?
И что там считать, все же элементарно. :)
Ну да. Придется сначала узнать какой длины пиксель. Потом сместиться на это число... Проще хочется. Как в C# :)


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Bepec от Декабрь 14, 2013, 11:58
ЫЫЫЫ... Какой длины пиксель?

PS прошу извинить за сей недостойный комментарий, но первая реакция всегда самая правдивая. И всё же, какой длины пиксель?


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 12:00
ЫЫЫЫ... Какой длины пиксель?
Ну да. 3 байта, 4 байта если с альфа каналом. Что не так? :)


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Bepec от Декабрь 14, 2013, 12:02
Непонятно мне зачем смещаться и что-то делать, если вам сразу даётся указатель на него? Нафига?


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 14, 2013, 12:04
Непонятно мне зачем смещаться и что-то делать, если вам сразу даётся указатель на него? Нафига?
Указатель на первый пиксель N строки. А мне к примеру нужно поработать с областью (64,64,10,10) в битмапе с разверткой 1280x800. Вот код на шарпе дает мне указатель на x,y точки.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 14, 2013, 12:14
А мне к примеру нужно поработать с областью (64,64,10,10) в битмапе с разверткой 1280x800. Вот код на шарпе дает мне указатель на x,y точки.
Напишите один раз такую функцию и пользуйтесь. Она будет очень простая.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Alex Custov от Декабрь 14, 2013, 15:14
Вот код на шарпе дает мне указатель на x,y точки.

Очевидно, что написать всё что можно внутри тулкита нельзя, всегда останутся недовольные. Такой функции нет видимо потому, что она никому не нужна была.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Bepec от Декабрь 14, 2013, 15:15
Я до сих пор в ней смысла не вижу :)


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 14, 2013, 16:53
Указатель на первый пиксель N строки. А мне к примеру нужно поработать с областью (64,64,10,10) в битмапе с разверткой 1280x800. Вот код на шарпе дает мне указатель на x,y точки.
"Учиться легко, трудно переучиваться"  :) Ведь код на шарпе был освоен и стал классикой, эталоном к которому нужно стремиться. Хотя с точки зрения программиста на С, он, мягко говоря, "очень затратный", да и удобством не блещет.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 08:34
А мне к примеру нужно поработать с областью (64,64,10,10) в битмапе с разверткой 1280x800. Вот код на шарпе дает мне указатель на x,y точки.
Напишите один раз такую функцию и пользуйтесь. Она будет очень простая.
Правильно мыслю?
Код:

QRect visibleRect = ....;

..............................

QImage currentRegionMap = getRegion(screen,visibleRect.x(),visibleRect.y(),visibleRect.width(),visibleRect.height());//Получаю область картинки...

int pixLen=currentRegionMap.bytesPerLine()/currentRegionMap.width();//Высчитываю длину пикселя

BYTE* a=currentRegionMap.bits();//Получаю указатель на "данные" картинки
BYTE* b=screenMap.scanLine(visibleRect.y())+(pixLen*visibleRect.x());//Тут получаю указатель на регион в другой картинке ...

Я до сих пор в ней смысла не вижу :)

Для вас нарисовал рисунок. Мне нужно сравнить картинку с регионом другой картинки. Попиксельно сравнивать медленно, гораздо быстрее так.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Bepec от Декабрь 18, 2013, 08:44
Спасибо за картинку, порадовали. Вот только это получение региона, отдельной части картинки.
А ему необходим указатель на начало данных.

PS в принципе это почти одно и то же, но всё же разные вещи ^.^


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 08:50
Спасибо за картинку, порадовали. Вот только это получение региона, отдельной части картинки.
А ему необходим указатель на начало данных.
PS в принципе это почти одно и то же, но всё же разные вещи ^.^
Я вас кажется тоже не понимаю :). Вроде понятно же.. Есть картинка 1 и есть картинка 2. Я хочу сравнить картинку 1 с регионом равным по размерам в картинке 2. Мне нужен указатель на начало данных в картинке 1 и указатеь на начало региона в картинке 2. Вот как получить указатель на начала региона в картинке 2? Я правильно мыслю...(смотреть код выше)?


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 08:52
Вот только это получение региона, отдельной части картинки.
Посмотрите пост #1. В C# я так и делаю.. Лочится память кокраз региона картинки и я получаю указатель на регион. Если можно сделать так же как в C#, то я буду очень рад.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 18, 2013, 10:42
Задача на 5 минут, неск дней обсуждаем  :)
Код
C++ (Qt)
bool CompareParts( const QImage & img1, const QRect & R1, const QImage & img2, const QRect & R2 )
{
if (R1.width() != R2.width()) return false;
if (R1.height() != R2.height()) return false;
 
int pixSize = img1.depth() / 8;
if (!pixSize || pixSize != img2.depth() / 8)
 return CompareByPixels(img1, R1, img2, R2);
 
for (int y = 0; y < R1.height(); ++y) {
  const uchar * src1 = img1.scanLine(y + R1.top()) + pixSize * R1.left();
  const uchar * src2 = img2.scanLine(y + R2.top()) + pixSize * R2.left();
  if (memcmp(src1, src2, R1.width() * pixSize) != 0) return false;
}
return true;
}


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 11:22
Задача на 5 минут, неск дней обсуждаем  :)
Код
C++ (Qt)
bool CompareParts( const QImage & img1, const QRect & R1, const QImage & img2, const QRect & R2 )
{
if (R1.width() != R2.width()) return false;
if (R1.height() != R2.height()) return false;
 
int pixSize = img1.depth() / 8;
if (!pixSize || pixSize != img2.depth() / 8)
 return CompareByPixels(img1, R1, img2, R2);
 
for (int y = 0; y < R1.height(); ++y) {
  const uchar * src1 = img1.scanLine(y + R1.top()) + pixSize * R1.left();
  const uchar * src2 = img2.scanLine(y + R2.top()) + pixSize * R2.left();
  if (memcmp(src1, src2, R1.width() * pixSize) != 0) return false;
}
return true;
}
Спасибо конечно, но вы не знаете всей задачи которую я решаю. Ваш код бесполезен для меня.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 18, 2013, 12:12
Спасибо конечно, но вы не знаете всей задачи которую я решаю. Ваш код бесполезен для меня.
Цитированием не злоупотрбляйте, незачем занимать тратить место если и так понятно на что Вы ответили.

Задачи Вашей я конечно не знаю - ну так Вам и карты в руки четко сформулировать вопрос. Если нужны "начала регионов", то их вычисления в приведенном коде есть. При этом однако нужно учитывать что "региона" никакого нет, а есть поле памяти где QImage хранит пиксели и Вы можете оперировать с нужным участком - но для каждой новой строки адрес придется вычислять. Это нормально, непонятно какие у Вас с этим трудности. Ну захотите - расскажете


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 12:24
Цитировать
Ну захотите - расскажете

Мне нужно получить участок памяти который отвечает за определенный участок изображения. Проще говоря как мне осуществить такое?
Код
C#
BitmapData btmData= currentRegionMap.LockBits(new Rectangle(x, y, width, height), ImageLockMode.ReadOnly, currentRegionMap.PixelFormat);
byte* a = (byte*)btmData.Scan0.ToPointer();
 


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 18, 2013, 12:37
Мне нужно получить участок памяти который отвечает за определенный участок изображения. Проще говоря как мне осуществить такое?
Чем раньше Вы перестанете ссылаться на "козырный С#" - тем лучше. Хорошо или плохо - но в таком-то языке вещи делаются так-то, это от нас не зависит. Примите это и не тормозите.

Возможно Вы хотели спросить "как получить НЕПРЕРЫВНЫЙ участок памяти?". Никак, (конечно за исключением "полных строк"). Можно только создать копию кусочка (QImage::copy), она будет непрерывна, но операция копирования затратна. Возможно Вы хотели что-то делать "одним куском" - так не выйдет, придется чуть-чуть повозиться со строками


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 13:28
Как 3 строку закрасить в черный цвет? Или как изменить значение пикселя по указателю? Спасибо. Не заметил просто :) Работает! Сейчас буду со строками эксперементировать.

Пробовал так:
Код:
    uchar * point= image.scanLine(2);

    for(int i=0;i<image.bytesPerLine();i++)
    {
        *point=0;
        point++;
    }


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 18, 2013, 13:34
Код:
    uchar * point= image.scanLine(2);

    for(int i=0;i<image.bytesPerLine();i++)
    {
        *point=0;
        point++;
    }
Не ошибка, но приятнее так
Код
C++ (Qt)
   memset(image.scanLine(2), 0, image.bytesPerLine());
 


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 13:53
Цитировать
Не ошибка, но приятнее так

Спасибо. Как получить скриншот в 24битной развертке? По умолчанию возвращает в развертке 4 байта на пиксель. Нужно 3 байта на пиксель.

Код:
QPixmap MainWindow::getScreenshot()
{
    QScreen *screen = QGuiApplication::primaryScreen();
    return screen->grabWindow(QApplication::desktop()->winId(),0,0,-1,-1);
}


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Alex Custov от Декабрь 18, 2013, 14:08
Спасибо. Как получить скриншот в 24битной развертке? По умолчанию возвращает в развертке 4 байта на пиксель. Нужно 3 байта на пиксель.

Преобразуй в QImage и дальше QImage::convertToFormat(). И начни читать документацию, там есть все ответы на твои вопросы.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 18, 2013, 14:29
Спасибо. Как получить скриншот в 24битной развертке? По умолчанию возвращает в развертке 4 байта на пиксель. Нужно 3 байта на пиксель.
Насколько я помню, 3 "нормальных" байт не получить, QImage::FormatRGB32 все равно хранит 4 байта на пыксель, просто альфа не используется. Реально все меньше 32 - дань истории, не связывайтесь с этим старьем


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 18, 2013, 14:39
Цитировать
Насколько я помню, 3 "нормальных" байт не получить, QImage::FormatRGB32 все равно хранит 4 байта на пыксель, просто альфа не используется. Реально все меньше 32 - дань истории, не связывайтесь с этим старьем

Мне бы как в C# :) PixelFormat.Format24bppRgb. Просто ведь тогда быстрее проверять буду разницу. И меньше в памяти занимать будет.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 18, 2013, 14:51
Мне бы как в C# :) PixelFormat.Format24bppRgb. Просто ведь тогда быстрее проверять буду разницу. И меньше в памяти занимать будет.
Чуть выше вам дали ответ на вопрос. Конвертируйте картинку в 24-битный формат QImage::convertToFormat() и QImage::Format_RGB888


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Igors от Декабрь 19, 2013, 10:50
Просто ведь тогда быстрее проверять буду разницу.
Пиксельные операции для 3 байт значительно медленнее чем для 4 (где можно привести к int). Да и даже не в этом дело. Любой имедж можно перегнать в ARGB32 и иметь всего 1 вариант кода. А начиная мутить с 3-мя байтами этой уверенности нет. Появится имедж с альфой - и опять придется суетиться, оно Вам надо?


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 20, 2013, 06:24
Ребята. Как прорисовать участок одного QBitmap в другой? Опять же на C# я делал так:

Код
C#
Bitmap newBitmap = new Bitmap(rects[i].Width, rects[i].Height, PixelFormat.Format24bppRgb);
Graphics graphics = Graphics.FromImage(newBitmap);
graphics.DrawImage(currentRegionMap, new Rectangle(0, 0, rects[i].Width, rects[i].Height), rects[i], GraphicsUnit.Pixel);
graphics.Dispose();


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 20, 2013, 07:13
QPainter::drawImage


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 20, 2013, 07:14
QPainter::drawImage
Спасибо. Кажется мне подойдет QImage::copy


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 22, 2013, 10:24
QPainter::drawImage
Не пойму как это использовать. Мне нужно один QImage нарисовать в другом QImage. Разобрался.


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Old от Декабрь 22, 2013, 10:29
Не пойму как это использовать. Мне нужно один QImage нарисовать в другом QImage.
Код
C++ (Qt)
QImage surf;
QPainter p( &surf );
p.drawImage( ... );
 


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 23, 2013, 06:27
Как можно напрямую скопировать участок из QImage в другой QImage? Такое возможно?
Сейчас скопирую так:
Код:
QPainter painter(&screenMap);
............................................................
painter.drawImage(QPoint(xPos[i],yPos[i]),regions[i]);


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: Alex Custov от Декабрь 23, 2013, 12:38
Как можно напрямую скопировать участок из QImage в другой QImage? Такое возможно?

Если я правильно понял, то QImage::copy(). Если неправильно, что через прямой доступ к байтам через QImage::bits()


Название: Re: Аналог LockBits, работа с битмапом
Отправлено: GPPsoft от Декабрь 24, 2013, 05:57
Сделал так. Не знаю.. может можно сделать оптимальнее? Вообщем я думаю это тоже самое что и QPainter::drawImage
Код:
void ScreenAnalyzer::copyRegion(QImage &srcImage, QImage &dstImage, int x, int y)
{
    int pixLen=3;
    int dstXOffset=pixLen*x;
    for(int i=0;i<srcImage.height();i++)
    {
        uchar* srcXPoint = srcImage.scanLine(i);
        uchar* dstXPoint = dstImage.scanLine(y+i);dstXPoint+=dstXOffset;
        memcpy(dstXPoint,srcXPoint,srcImage.width()*pixLen);
    }
}