Название: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 21, 2011, 13:56 Всем привет!
Мне нужно написать программку, которая в многопоточном режиме осветляет пиксели на картинке. У меня есть документация по работе с потоками в Qt, но, что касается самого осветления пикселей...даже не представляю, с чего начать. Подскажите, кто знает, как это делается. Благодарю. Название: Re: Многопоточное осветление пикселей Отправлено: LisandreL от Ноября 21, 2011, 14:08 что касается самого осветления пикселей...даже не представляю, с чего начать. Что вы подразумеваете под осветлением? Увеличение I в HSI?Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 21, 2011, 15:10 У меня нет опыта а в обработке изображений. Просто нужно написать небольшую демонстрационную программку.
Программа, демонстрирующая преимущества многопоточности в Qt. В качестве работы для потоков, решил сделать осветление пикселей. >> Увеличение I в HSI? Не совсем понимаю вопрос. Ну суть какова: мы выбрали картинку, загрузили её в программу (QPixmap или QImage, что лучше?)). Далее в многопоточном режиме осветляем картинку пиксель за пикселем. Осветление - оно и есть осветление, сделать картинку чуть ярче, что-ли. Название: Re: Многопоточное осветление пикселей Отправлено: LisandreL от Ноября 21, 2011, 15:39 >> Увеличение I в HSI? http://ru.wikipedia.org/wiki/HSIНе совсем понимаю вопрос. Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 21, 2011, 17:31 Так вполне устроит HSV модель. Берете пиксель (RGB). перегоняете его в HSV (QColor::getHsv), увеличиваете V и записываете назад в RGB (QColor::setHsv). Каждой нитке даете определенное число строк для обработке (проще всего)
Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 23, 2011, 18:51 Спасибо, помогло!
Продолжу работать над программой... Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 24, 2011, 12:25 Такой вопрос:
Определил класс для многопоточного осветления пикселей Код: class ImageThread : public QThread { ... }; В главном классе создаю несколько потоков: Код: for(int i = 0; i < threadsLimit; i++) При выводе отладочной информации, qDebug показывает, что у всех потоков один и тот же идентификатор. Например: При threadsLimit = 1, qDebug показывает: Код: ID: 0xc10 При threadsLimit = 2, qDebug показывает: Код: ID: 0xc10 При threadsLimit = 3, qDebug показывает: Код: ID: 0xc10 Может я где-то ошибся и, действительно, создаётся только один поток? Название: Re: Многопоточное осветление пикселей Отправлено: BRE от Ноября 24, 2011, 12:31 Потоки запускаются методом start!!!
Название: Re: Многопоточное осветление пикселей Отправлено: Bepec от Ноября 24, 2011, 13:23 run - выполнение функции run;
start - запуск потока, который выполняет функцию run; Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 24, 2011, 15:14 Ок, с этим ясно.
Возникла другая проблема. При запуске программы в одном потоке, проблем нет. Но если запускать её хотя бы в двух потоках, то программа вылетает. Просто завершается с кодом "-1073741819" или ему подобным. Тут запускаем потоки из главного класса: Код: for(int i = 0; i < threadsLimit; i++) А вот метод run(). Указатель на картинку (QImage) получаем из главного класса, по этому блокируем её мьютексом. Код: void ImageThread::run(){ Из отладочной информации тоже не стало ясно, почему программа вылетает. Завершение происходит ни на одном и том же месте, а в разных местах: то на записи обработанного пикселя, то на увеличении яркости. Ещё одна странность. Из отладки видно, что при запуске программы в двух потоках, получает управление только один поток. Этот поток входит в цикл и начинает работать, но другого потока нет. Этот один поток продолжает работать, а потом программа вылетает. Вот отладочная информация: Код: Видим, что поток с ID 0xcd8 вошёл в метод, вошёл в первый цикл и во второй. Не могу понять, в чём проблема. Подскажите, где я ошибся? Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 24, 2011, 16:06 Писал прямо здесь, ошибки возможны
Код
Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 24, 2011, 19:29 В циклах всё понятно, код замечательный у Вас ))
Не понятно только вот здесь: Код: // mSelfIndex - индекс нитки mTeamCount - кол-во созданных потоков, полагаю? А вот mSelfIndex? Индекс... в смысле идентификатор потока? Или его порядковый номер? Вот тут что-то не совсем понял... Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 24, 2011, 19:57 А вот mSelfIndex? Индекс... в смысле идентификатор потока? Или его порядковый номер? Порядковый - нитке нужно знать какие строки имеджа она будет обрабатывать. Просто передавайте в конструктор и еще: лучше сделать контейнер указателей (а не самих ImageThread), напрВот тут что-то не совсем понял... Код
Название: Re: Многопоточное осветление пикселей Отправлено: Sahab от Ноября 24, 2011, 21:42 OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B)
Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 24, 2011, 22:14 OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B) В данной задаче OpenMP ни к селу ни к городу. Ну разве что есть желание "пособирать" :)Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 24, 2011, 22:56 Идея с контейнерами хороша. Но видите ли, задача данной программы: продемонстрировать преимущества многопоточности.
Программа рассчитана на слабую аудиторию, которая и в программировании-то не особо сильна, а Qt и в глаза не видела. По этому хотелось бы сделать код на столько простым, насколько это вообще возможно. Igors, спасибо за помощь! Я учту Ваши советы и продолжу работать над программой, однако, считаю, что контейнеры включать не стоит, т.к. из аудитории с STL врятли кто знаком. В данном случае, главным является простота кода, пусть даже в ущерб эффективности. Название: Re: Многопоточное осветление пикселей Отправлено: Sahab от Ноября 24, 2011, 23:06 OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B) В данной задаче OpenMP ни к селу ни к городу. Ну разве что есть желание "пособирать" :)учитывая Цитировать Программа, демонстрирующая преимущества многопоточности в Qt. - то не подойдет.если осветление пикселей в отдельном потоке - тоже. если Цитировать Многопоточное осветление пикселей то вполне подойдет.хотя все это оффтоп Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 24, 2011, 23:44 Igors, Я изменил метод run() в соответствии с Вашими рекомендациями, но проблема осталась.
Пытаясь локализовать ошибку, я выводил отладочную информацию в каждом потоке, она состоит из сообщения о том, что поток с определённым ID начал работу, общее кол-во потоков, номер выполняемого потока, и сообщение о том, что поток завершился. Вот отладочная информация при 1-м потоке: Код: thread begin # 0xf60 При 2-х потоках: Код: thread begin # 0xc2c При 3-х потоках: Код: thread begin # 0x208 При 4-х потоках: Код: thread begin # 0x5fc Завершается первый созданный поток и завершается вся программа. Тут явно что-то не так... Но я никак не могу понять, что именно... Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 25, 2011, 10:43 Примерный код главной нитки
Код Минус "просто массива" в том что нельзя передать параметры в конструктор каждого элемента, ну это можно перетерпеть Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 27, 2011, 12:28 Фуууух, наконец-то нашёл, в чём проблема.
Первый поток работает с указателем t_image, который указывает на QImage, содержащий картинку. Когда начинает работать второй поток, указатель t_image почему-то содержит уже другой адрес, а потому программа и вылетала. Сделал указатель t_image статическим, проблема решилась. Igors, большое спасибо за помощь! Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 28, 2011, 19:20 Прям какое-то колдовство!
Работала программа, всё замечательно, и тут СНОВА та же проблема. При запуске программы в нескольких потоках, она вылетает. Отладчик показал, что программа вылетает из-за ошибки сегментации (SIGSEGV). И вылетает на этой строке: Код: color.setRgb(qRed(pix), qGreen(pix), qBlue(pix)); Но гораздо чаще, вот на этой: Код: pix = qRgba(color.red(), color.green(), color.blue(), qAlpha(pix)); Сколько уже с ней провозился, никак не могу понять, в чём тут дело... Если кто знает, подскажите, пожалуйста. Ниже привожу код: Код: void ImageThread::run() Запускаем потоки: Код: // кол-во потоков Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 28, 2011, 20:24 1) Надо верить "самому себе", (ну или "уважать себя" - смысл тот же). Мы сказали/утверждаем что каждая нитка работает со своей частью имеджа, таким образом нитки не пересекаются. Значит нехрен боязливо вставлять мутексы "на всякий случай" - тем более что вылетов они все равно никак не ловят.
2) По каким-то сторонним причинам мы не хотим делать нормальный контейнер указателей - но мы запрашиваем число ниток у пользователя. Ладно, так надо - значит надо, Вам виднее. Но тогда надо как минимум проверять не превысит ли введенное пользователем число ниток размер массива. Плюс называть вещи своими именами, а не так себе Код Откуда видно что это static? Никак не видно. давайте так Код Вот это static и это ясно без комментариев 3) Вылетает - нормально, у меня тоже ни одна multi-threaded задача сходу не пошла (на то она и multi-threaded). Спокойно вставляем отладочную печать в run нитки, напр Код
Др. словами - надо почиститься, навести порядок - и все получится (куда она денется) Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 29, 2011, 00:09 1) Когда я только начинал изучать потоки, вычитал, что доступ к совместно используемым данным, нужно блокировать мьютексом.
Ну вот это правило себе в голову сразу и вбил. Собственно, да, в этом случае мьютексы и не нужны, можно их убрать. 2) Да, в программе задаётся массив ImageThread imgThread[4]; , а кол-во нужных потоков, пользователь выбирает сам. Пользователь не сможет задать более 4-х потоков, спасибо QSpinBox'у, который задаёт ограничение. К слову о статических данных, тут Вы абсолютно правы, я недоглядел. 3) В каждой итерации второго (вложенного) цикла, вывожу отладочную информацию, такой строкой: Код: qDebug() << "#" << this->currentThreadId() Получаем следующий вывод. Первый запуск (2 потока). (в связи с большим кол-вом информации, часть заменена на "..."): Код: # 0x928 img: 0x41602c team_count: 2 self_index: 0 row: 0 col: 0 begRow: 0 endRow: 97 Второй запуск, 2 потока, другое изображение: Код: # 0x220 img: 0x41602c team_count: 2 self_index: 0 row: 0 col: 0 begRow: 0 endRow: 302 Дебаггер так же сообщает об ошибке сегментации. Останавливается на строке Код: color.setRgb(qRed(pix), qGreen(pix), qBlue(pix)); и о &pix <not accessible>. В отладочной информации, я не заметил ничего необычного, хотя...может плохо смотрел. Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 29, 2011, 10:39 1) Когда я только начинал изучать потоки, вычитал, что доступ к совместно используемым данным, нужно блокировать мьютексом. Все Вы правильно вычитали, но у Вас "идеальный случай" когда можно (и нужно) обойтись без блокировок3) В каждой итерации второго (вложенного) цикла, вывожу отладочную информацию, такой строкой: Оба-на - ведь должна быть одна печать на 1 нитку, и все. Почему вторая печатается много раз? Баг, разбирайтесь. И что значит "второго" - непонятно где тут "вложенный", пояснитеПолучаем следующий вывод. Первый запуск (2 потока). (в связи с большим кол-вом информации, часть заменена на "..."): Код: # 0x928 img: 0x41602c team_count: 2 self_index: 0 row: 0 col: 0 begRow: 0 endRow: 97 Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 29, 2011, 11:01 Ну как же?
Код: for(int row = beginRow; row < endRow; ++row){ // первый цикл Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 29, 2011, 11:29 Нет, перенесите печать выше, сначала надо убедиться что все нитки "получили свои куски". Плюс последнюю строку (выдача сигнала) для отладки лучше закомментировать
Если случай "совсем тяжелый" и/или "надо срочно" - скиньте исходники, можно в личку Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 29, 2011, 12:25 Перенёс вывод отладочной информации в первый цикл, получил следующее:
Код: # 0xfc8 img: 0x41602c team_count: 2 self_index: 1 row: 302 begRow: 302 endRow: 604 Случай не то, чтобы совсем уж тяжёлый, но проблематичный. Исходники прямо сюда скину, у меня секретов нет. Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 29, 2011, 13:59 Собрал, посмотрел, все "как доктор прописал" (Picture 1) - только вот чего Вы wait закомментарили (Picture 2)? Так нельзя, главная нитка обязательно должна дождаться пока все рабочие завершатся. Оно конечно имя "wait" неинтуитивное (в оригинале pthread_join) но тем не менее.
К слову: не пишите русских комментариев, как правильно советует наш модератор (Picture 2). Рано или поздно "plain English" придется освоить, так что затягивать незачем. Если вылет на др. имедже - загрузите, т.к. пока нечего искать Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 29, 2011, 17:24 чего Вы wait закомментарили? Думал, что wait тут не нужен. Понятное дело, что в случае консольной программы, главный поток должен ждать завершения дочерних. Но вот не думал, что это нужно делать и в программах с GUI, т.к. главный поток не завершится после запуска дочерних.Цитировать не пишите русских комментариев. Рано или поздно "plain English" придется освоить Да с Английским у меня проблем особых нет. В данном случае комментарии на Русском т.к. программа предназначена для слабой аудитории, которая не сильна ни в программировании, ни в Английском. По этому решил, что комментарии на Русском будут проще для восприятия.Цитировать Если вылет на др. имедже - загрузите, т.к. пока нечего искать ...Что-то не уловил мысль...Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 29, 2011, 19:28 Если вылет на др. имедже - загрузите, т.к. пока нечего искать ...Что-то не уловил мысль...Примечание: менять "saturation" тоже очень полезно/наглядно, даже чаще нужно чем "value". Я бы добавил опцийку (совсем недавно писал такой шейдер). Ну и слайдеры бы неплохо смотрелись (впрочем дело вкуса) Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 29, 2011, 22:42 У Вас программа не падает? ...хм...да в чём же дело...
В папке images, 2 изображения. Что на первом, что на втором программа вылетает. Вот например, image1, 2 потока - и программа падает. Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Ноября 30, 2011, 11:27 У Вас программа не падает? ...хм...да в чём же дело... Давайте имеджи, посмотрим по-живому. У меня (пока) все норм.В папке images, 2 изображения. Что на первом, что на втором программа вылетает. Вот например, image1, 2 потока - и программа падает. Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 30, 2011, 14:27 ...хм...странно получается...
вот картинки. интересно разобраться, в чём же тут дело. Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Ноября 30, 2011, 17:28 Как программа повела себя у Вас с этими картинками?
Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Декабря 01, 2011, 13:12 Нормально повела :) Единственное что я сделал - раскомментарил wait. По поводу workThread - он у Вас правильно вызывается, срабатывает QueuedConnection, но смысла немного, все равно надо "дождаться всех" и это время уже печатать (после wait). А если хотите иметь еще и время выполнения каждой, то проще сохранить в члене класса imageThread. Заодно присмотритесь к threadWorkDone, он объявлен с аргументом const QString & а для connect не так - во всяком случае проще сделать однообразно.
Название: Re: Многопоточное осветление пикселей Отправлено: AlphaGh0St от Декабря 01, 2011, 21:51 Igors, представляете, под виндой компилировал и запускал программу, так она при работе более, чем в двух потоках вылетала. А сейчас, эксперимента ради, решил перекомпилировать и запустить под Линукс, и о чудо, всё заработало!
Программа прекрасно работает с разными изображениями и с разным количеством потоков. Это, кончено, замечательно, но всё же не понятно, почему так произошло... Igors, спасибо Вам за помощь! Название: Re: Многопоточное осветление пикселей Отправлено: daimon от Января 16, 2012, 16:33 под виндой на статике вылет, начиная уже с 2 потоков
Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Января 16, 2012, 17:14 1) Проверьте что скомпилено как "Multithreaded DLL"
2) Закомментите отот emit workDone (он вообще "левый", зачем выводить имедж, если только одна нитка отстрелялась - ведь другие еще могут работать) 3) где-то t_Image калечится, гляньте data, row, column и попробуйте отловить напр так Код
Название: Re: Многопоточное осветление пикселей Отправлено: daimon от Января 17, 2012, 01:21 1) Проверьте что скомпилено как "Multithreaded DLL" 2) Закомментите отот emit workDone (он вообще "левый", зачем выводить имедж, если только одна нитка отстрелялась - ведь другие еще могут работать) 3) где-то t_Image калечится, гляньте data, row, column и попробуйте отловить напр так Код
я специально ушел от рантайма, и скомпилил qt статикой и без рантайма Код ассерт не вылетает, но приложение вылетает проблема здесь unsigned int &pix = data[column]; по картинке видно, что вылет идёт на втором потоке - осветлена половина Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Января 17, 2012, 13:34 - Перенесите (первый) testScan выше, до цикла по строкам
- отключите emit workDone, наиболее вероятно там порылась собака - значения переменных на момент вылета (row, column, dat)? Название: Re: Многопоточное осветление пикселей Отправлено: daimon от Января 17, 2012, 14:51 - Перенесите (первый) testScan выше, до цикла по строкам - отключите emit workDone, наиболее вероятно там порылась собака - значения переменных на момент вылета (row, column, dat)? если емит убираю, оно не выводит результат на экран Название: Re: Многопоточное осветление пикселей Отправлено: Igors от Января 17, 2012, 15:20 если емит убираю, оно не выводит результат на экран Так выведите после того как все нитки отработали.Ну а с вылетом-то что? Где Вы учились на партизана? Так не можнА :) Название: Re: Многопоточное осветление пикселей Отправлено: Fregloin от Января 18, 2012, 12:49 здесь бы в тему был как раз OpenCL!
Название: Re: Многопоточное осветление пикселей Отправлено: lolbla2 от Февраля 25, 2012, 19:16 - Перенесите (первый) testScan выше, до цикла по строкам - отключите emit workDone, наиболее вероятно там порылась собака - значения переменных на момент вылета (row, column, dat)? если емит убираю, оно не выводит результат на экран Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ? ??? Название: Re: Многопоточное осветление пикселей Отправлено: LisandreL от Февраля 25, 2012, 20:00 Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ? А в чём проблема?Поддержка компиляторов MS VC 2005/2008/2010 сейчас идёт в составе Qt SDK. Ну а если разрабатывать в студии хочется, то есть Qt VS Add-in для студий выше экспресса. Название: Re: Многопоточное осветление пикселей Отправлено: lolbla2 от Февраля 26, 2012, 09:58 Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ? А в чём проблема?Поддержка компиляторов MS VC 2005/2008/2010 сейчас идёт в составе Qt SDK. Ну а если разрабатывать в студии хочется, то есть Qt VS Add-in для студий выше экспресса. Ну да получается в студию (в саму IDE) можно встроить Qt библиотеки? Меня конечно и Qt Creator устраивает, но просто удивило, не знал что так можно... Название: Re: Многопоточное осветление пикселей Отправлено: alexksv2010 от Февраля 29, 2012, 13:19 Если вопрос еще не решен, то столкнулся со схожей проблемой...
И решил ее следующим образом: 1. Контейнерами: Ошибка: Программа почему-то обнуляла контейнер (Несмотря на то, что кроме потока с ним никто не работал) Решил это просто заперев функцию мьютексами QMutex mutex.lock() вначале и mutex. unlock() в конце. 2. Общение из потока с главным потоком приводит к тому, что сигнал не всегда генерируется... Решил с помощью: class RequestEvent:public QEvent { public: PointArray val; RequestEvent(PointArray vl); }; QCoreApplication::postEvent(parent,new RequestEvent(request),Qt::HighEventPriority); |