Задать вопрос
Ответы пользователя по тегу C++
  • Какие есть библиотеки для работы с RAW изображениями?

    @Mercury13
    Программист на «си с крестами» и не только
    1. RAW есть несколько штук: RAW CHDK, CRW Canon, NEF Nikon, платформонезависимый, но мало кем используемый DNG…
    2. Если у вас графической редактор общего назначения, крайне не советую. Для «проявки» RAW нужен особый инструментарий, которого в редакторе общего назначения нет. Плюс куча очень умных вещей, вроде дебайеризатора и шумодава. Оставьте это лайтрумам!
    XnView, допустим, смотрит, но получается дрянь — в CHDK RAW все эти дебайеризации и кривые яркости сделаны как попало, и шумодава никакого. Хотя формат, признаться, редкий, Adobe его берёт только через промежуточный платформонезависимый DNG.
    В Nikon NEF, по-видимому, смотрит превьюху: нет никакой разницы с Medium JPEG — любая программа проявки хоть где-то да проявит свой характер. Впрочем, одна есть: адовы искажения, присущие пережатому JPEG. К тому же снял в ч/б — он и вывел ч/б, в отличие от DxO, которому надо ещё указать, что формат с матрицы надо ещё в ч/б конвертнуть.
    (Других фотоаппаратов у меня не было.)
    Но XnView — просмотрщик, ему позволительно, он должен поддерживать как можно больше форматов и показывать их, пускай как попало.
    Фотошоп открывает, но там этот инструментарий в каком-то виде есть, и под капотом нечто очень умное, на голову превосходящее внутрикамерную проявку мыльниц Canon (зеркалку Nikon не проверял). Но и они собрали все свои наработки по RAW и сделали отдельную программу специально для проявки цифрофото — Lightroom.
    3. Обратно в RAW в принципе не стоит. Это файл с матрицы фотоаппарата, и точка. Вы что, хотите снимки подделывать?

    UPD. Ясно, вы решили именно проявлять несколько кадров в один HDR…
    Тогда задача библиотеки — дебайеризовать, возможно, подавить шум, И ВСЁ. Вам нужны картинки в ЛИНЕЙНОМ цветовом пространстве с 16-ю битами на канал. Обычная проявка в JPEG (BMP, TIFF) НЕ КАТИТ, у них по умолчанию ГАММА-СКОРРЕКТИРОВАННОЕ пространство и единица около нуля не равна единице около 255. Скажем так: на экране, чтобы выделялось на чёрном фоне, надо осветлять почти на 60 единиц, на белом — затемнять на 16.

    Остальную магию вы уж как-то сами проведите. 1) Подправьте искажения объектива (как геометрические, так и цветовые). 2) Склейте три кадра в один с дробным цветовым пространством. 3) Придумайте, как всё это чудо свести в узкий диапазон экрана. 4) Наладить все эти гамма-коррекции и прочие кривые. 4) И только тогда преобразовать в целое [0…255].
    Ответ написан
    2 комментария
  • Не могу найти ошибку в использовании long double в C?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня всё сработало. Может, зависит от библиотеки Си? Какой компилятор?

    UPD. Сработало на MinGW.
    Ответ написан
    1 комментарий
  • Почему меняется выходное значение после нескольких запусков программы?

    @Mercury13
    Программист на «си с крестами» и не только
    Компилятор какой используете? У меня на MinGW всё постоянно — и постоянно не дробная часть. Есть две возможные причины нестабильного поведения.
    1. Флаги сопроцессора — какая-то библиотека Си их не выставляет в постоянное значение.
    2. Неопределённое поведение (uint32_t)var в предпоследней строке. Число-то >1016, а uint32 — это 4·109.

    Тут вы множите число на 10, пока оно не станет целым. Если оно не точный double (а оно не точный), получается ситуёвина, когда младшие биты зависят от флагов сопроцессора, и неизвестно, сколько итераций проработает программа. В любом случае крайне мала вероятность, что будет нечто умещающееся в uint32_t. Таким образом, есть такие варианты обойти проблему.
    1) Умножить сразу на 1e8, а затем обрезать нули.
    2) Сконвертировать в uint64_t.

    Преобразование в uint64_t даёт постоянные 28800000000000024.
    Умножение на 1e8 (число подобрано такое, чтобы в uint32_t вмещалось)
    var *= 1e8;
        number = (uint64_t)var;
    
        while (number % 10 == 0)
            number /= 10;

    даёт 288.

    UPD. Сам я для преобразования дробного в строку в коммерческой проге использую собственную функцию, основанную на GRISU. Там есть много функций наподобие: точность 7 знаков, но если число <1010 — выводим его как целое, с 9-ю знаками.
    Ответ написан
    Комментировать
  • Почему код не работает C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Этим переменным не присваивали начального значения и в них могло оказаться что угодно.

    Переводите с английского!
    Ответ написан
    8 комментариев
  • Как реализовать сумму дробей?

    @Mercury13
    Программист на «си с крестами» и не только
    Заводим структуру-сумматор. Изначально она 0/1. Что-то типа
    typedef struct {
      int num, den;
    } Fraction;
    
    …
    
    Fraction sum = { 0, 1 };

    Дальше пишу псевдокодом, НОД и НОК разберись, как реализовать самому.
    для каждой очередной дроби
      ввести(дробь)
      новыйЗнам = НОК(сумматор.знам, дробь.знам)
      множСумм = новыйЗнам / сумматор.знам
      множДробь = новыйЗнам / дробь.знам
      новыйЧисл = сумматор.числ × множСумм + дробь.числ × множДробь
      сокрНод = НОД(новыйЧисл, новыйЗнам)
      сумматор.числ = новыйЧисл/сокрНод
      сумматор.знам = новыйЗнам/сокрНод

    Можно и оптимизировать, но тогда нужна хитрая разновидность алгоритма Евклида; в учебных целях не стоит.

    И ещё. Одна из известных ошибок в написании НОК — произведение аргументов не влезает в свой тип, а НОК влезает. Поймёшь, как в такой ситуёвине избавиться от переполнения?
    Ответ написан
    Комментировать
  • Как разобратся с кодом?

    @Mercury13
    Программист на «си с крестами» и не только
    Матрица имеет вид «хребта», на котором висят массивы-строки.

    Вставка работает так.
    1. Завести новый хребет.
    2. Завести новую строку.
    3. Посадить все остальные строки на новый хребет.
    4. Перенести новую матрицу на место старой.

    Удаление работает точно так же, только без 2.

    Как избавиться от говнокода.
    1. Стоило бы разделить интерактивное удаление и собственно удаление.
    2. Стоило бы тащить this (с какой матрицей работаем). А то на данный момент работаем с одной матрицей, и точка.
    3. Если уж методы — может, стоит писать в объектном стиле?
    4. Снова-таки, утечки памяти!
    Ответ написан
  • Как передать двумерный динамический массив в другую функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть два способа наладить динамический 2D-массив: «хребет» и «линейный массив».

    Хребет определяется как int** a = new int*[m];
    А затем каждый элемент хребта присваиваете new.
    Доступ a[i][j].

    Линейный массив определяется int* a = new int[m*n];
    Доступ a[i*n + j].

    Ваш случай — линейный массив, то есть
    void func(int a[], int n, int m)
    …
    func(a[0], n, m);


    Советую как-то заинкапсулировать эти массивы и передавать
    void dumpArray(const Array2D& x)
    К сожалению, у инкапсулированного массива нет хорошего способа сделать a[i][j], но можно a(i,j).
    Ответ написан
    2 комментария
  • Можно ли вынести реализацию шаблонного класса в отдельный cpp файл?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно в таких случаях.
    1. Если у шаблона ровно N специализаций и (N+1)-й быть не может.
    2. Если он private и его синтаксически невозможно вызвать откуда-то ещё, кроме CPP.
    3. template<> (полностью специализированная функция без шаблонных параметров). Ей место именно в CPP, если она общедоступная и не inline.

    Стек, очевидно, ни к одному из этих случаев не относится.

    Код создаёт не сам шаблон, а его расшаблонивание!
    Ответ написан
    Комментировать
  • Что означают эти строки в коде?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Указатель на указатель. Мы создаём 2D-массив как кучу динамических 1D-. Если 1D-массив — указатель, то массив из таких 1D- — массив из указателей, то есть указатель на указатель.
    2. Указатель простой (создать 1D-массив из указателей, который станет «хребтом» нашего 2D-).
    Ответ написан
    5 комментариев
  • Какие dll добавить в проект Qt, чтобы на удаленном компьютере работал доступ к MySQL?

    @Mercury13
    Программист на «си с крестами» и не только
    Если с MySQL работаем напрямую, то
    plugins\sqldrivers\qsqlmysql.dll
    libmysql.dll
    Ответ написан
    4 комментария
  • Как переставить в обратном порядке элементы массива, расположенные между его минимальным и максимальным элементами?

    @Mercury13
    Программист на «си с крестами» и не только
    Найти индекс минимального и максимального.
    Если нужно, поменять местами, чтобы один был меньше другого. ИНДЕКСЫ, не элементы.
    А теперь цикл.
    ++низИндекс
    --верхИндекс
    пока низИндекс < верхИндекс
      поменять a[низИндекс], а[верхИндекс]
      ++низИндекс
      --верхИндекс

    Если индексы беззнаковые, надо проверить как-то, что первое --верхИндекс не приведёт к «антипереполнению». Например, «если верхИндекс > 0»…
    Ответ написан
    Комментировать
  • Как подключиться к MySQL из Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужны две DLL’ки: libmysql.dll в каталоге с программой, и qsqlmysql.dll в каталоге plugins/sqldrivers.
    От подкаталога plugins можно избавиться, написав в программе

    QApplication a(argc, argv);   // это наша программа, обычно создано автоматом
    a.addLibraryPath(QCoreApplication::applicationDirPath());


    От sqldrivers, насколько мне известно, так нельзя.
    Ответ написан
    Комментировать
  • Как QFileDialog вывести диалог открытия файла и получить имя файла в char?

    @Mercury13
    Программист на «си с крестами» и не только
    this — это скрытый параметр каждого не-static-метода, который говорит: для какого объекта он вызван. Если этот объект не QWidget, или функция static, или вообще не метод, то или подставляйте другой QWidget (это значит: кнопка на панели задач та же, что и у этого QWidget), или ставьте NULL (завести новую кнопку на панели задач).

    В вашем случае, разумеется, NULL. Или nullptr, если работаете в Си++11.

    QString *qs = new QString("переведи меня в чары! :)");
    char const* ch = qs->toLocal8Bit().constData();

    Верно придумали, только нет нужды заводить строку в куче операцией new. Строка в Qt и так достаточно «экономная», так что хватит
    QString qs("переведи меня в чары! :)");
    char const* ch = qs.toLocal8Bit().constData();

    Только не забывайте про время жизни этого char const*: он будет жить ровно столько, сколько будет жить конкретное значение строки.
    Ответ написан
    Комментировать
  • Можно ли в C++ узнать позицию с которой начинается подстрока без перебора символов в строке?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Надо проверить pSubStr на NULL. Если оно так — не найдено.
    2. Всё наоборот, pSubStr - str.
    Ответ написан
    Комментировать
  • Запуск консольного приложения при перетаскивании на него файла Drag&Drop C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Перетаскивание просто запускает программу, подставив имя файла как параметр командной строки. Те самые argc и argv, передаваемые в main().

    Кроме того, очень желательно (если у вас Windows) работать в Юникоде (в MinGW настройка компилятора -municode, для других компиляторов разбирайтесь сами). Функция main меняется на _wmain, её параметры на int argc, wchar_t** argv. Хотя не обязательно, если пути не содержат расширенных символов.
    Ответ написан
    1 комментарий
  • Почему не видит функцию из библиотеки в Ардуино?

    @Mercury13
    Программист на «си с крестами» и не только
    Запомни раз и навсегда! Inline не создаёт кода, создаёт факт его использования где-либо.
    С одной стороны, inline-функция при каждом использовании должна быть определена. С другой, она не попадёт в объектный файл сама по себе.
    Потому inline держат в хедерах (кроме хитрых случаев вроде private inline, когда синтаксически нельзя эту функцию вызвать откуда попало, а хедер лучше не засорять).

    Когда доберётесь до шаблонов Си++ — они обладают теми же свойствами. Шаблон не создаёт кода, создаёт расшаблонивание. И тоже в хедерах, кроме хитрых случаев вроде private template или шаблона, у которого есть ровно N предопределённых специализаций и (N+1)-я не нужна.

    А вот полная специализация шаблонной функции типа template<> (в угловых скобках пусто, не inline) создаёт и ей место в CPP.
    Ответ написан
    4 комментария
  • Как сделать и вывести срез строки(String) C/C++?

    @Mercury13
    Программист на «си с крестами» и не только
    1.
    std::cout << text.substr(начало, длина) << std::endl;

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

    2. Ничего, что, если строка не оканчивается точкой, последнее «недопредложение» выведено не будет? Может быть, так и верно, но если задача — разделить текст по tab’ам или запятым, надо после цикла выкинуть то, что осталось.
    Ответ написан
    Комментировать
  • Удаление объекта в C++ без создания его через new, или можно ли удалять объекты взятием адреса (&)?

    @Mercury13
    Программист на «си с крестами» и не только
    > Объект BaseClassObj будет удален только по завершению программы.
    BaseClass baseClassObj;
    Здесь создаётся объект на стеке. Имя — это просто имя объекта. Никаких указателей здесь нет. Как только мы покинем блок (любым образом: штатно выйти, goto, break, выброс аварии — кроме «жёсткого» выхода из программы функциями типа exit), у объекта автоматически исполнится деструктор и прямой вызов не нужен. Блок, то есть подпрограмму BaseClassPresentation.

    BaseClass *BaseClassObjPtr = new BaseClass(2);
    Здесь BaseClassObjPtr это имя указателя (а не указатель на указатель). Объект создаётся в динамической памяти, и его придётся уничтожать вручную. Многое в Си++11 сделали для того, чтобы подобные объекты уничтожались не вручную, а всё теми же автодеструкторами.
    std::unique_ptr<BaseClass> BaseClassObjUp = new BaseClass(2);
    Это уже маленький объект со своим деструктором. А в деструкторе находится delete, и он сработает, как только программа выйдет из своего блока.

    То, что вы хотите, иногда бывает нужно, и я вижу этому две причины.
    1. Объект управляет какими-то сложными и важными ресурсами: большим количеством памяти, файлом, мьютексом… И этот важный ресурс бывает нужно освободить раньше, чем наступит деструктор. Например, у любого файлового потока есть функция close() — она закрывает файл.
    2. У нас сложное и хитрое управление памятью, когда приходится использовать placement new и прямой вызов деструктора. Скажу честно, не использовал никогда. Как и 90% программистов на Си++.
    Ответ написан
    9 комментариев
  • При компиляции VC++, Opencv 3.2 проекта не работает exe на другой системе, требует opencv_world330.dll что делать?

    @Mercury13
    Программист на «си с крестами» и не только
    Краш, вероятно, связан с другой вещью. Компилятор-то новенький, и на ту машину не успели подвезти его среду исполнения. Выясни, какие файлы нужны: MSVCR140.DLL, MSVCP140.DLL или MFC140U.DLL.
    (при условии, что сам OpenCV также скомпилирован C++2017; если нет — также нужны и файлы другого компилятора.)

    Если так и не удастся отыскать — найди программу Dependency Walker и точно найди, чего ей не хватает.
    Ответ написан
    6 комментариев
  • Как правильно из zip архива считать текстовый файл с помощью PHYSFS?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно закрыть Си-строку.
    int length = PHYSFS_fileLength(myfile)
    myBuf = new char[length + 1];
    int length_read = PHYSFS_read(myfile, myBuf, 1, length);
    myBuf[length_read] = 0;
    Ответ написан
    Комментировать