К содержимому
ИС30

Поиск по сайту

Конспекты, лабы, квизы, ЧаВо и страницы

Войти
Инструментальные средства разработки ПО
ИСРЛаба 6

Водяной знак на BMP (командный проект)

Командный проект на троих: программа на C++ накладывает водяной знак на 24-битное BMP, работа ведётся в общем репозитории на GitHub, сборку и тесты проверяет GitHub Actions.

Хегай Максим Вилорьевич
Дедлайн
пятница, 4 декабря
до 23:59
Через 40 днейДедлайн мягкий: сдать можно и позже, но лучше не тянуть
Войти, чтобы записаться на сдачу
Войдите

Задание

Командный проект на троих: программа на C++, которая накладывает водяной знак (второе BMP-изображение) на исходное BMP и сохраняет результат в новый файл. Вся работа ведётся в общем репозитории на GitHub, сборку и тесты проверяет GitHub Actions.

Цель — не только сама программа, но и совместная работа с Git: ветки, слияния, разрешение конфликтов, Pull Request’ы и код-ревью, понятная история коммитов от каждого участника.

Роли в команде

Студент 1 — класс для BMP

  • Класс (например, ImageBMP) с полями ширины, высоты, глубины цвета и массивом пикселей, методы load(filename) и save(filename).
  • Чтение и запись через std::ifstream / std::ofstream с флагом std::ios::binary, проверка is_open() и того, что прочитано столько байт, сколько ожидалось.
  • Разбор заголовков вручную, без готовых библиотек для изображений: #pragma pack(push, 1)-структуры под BITMAPFILEHEADER и BITMAPINFOHEADER или чтение полей по одному.
  • Учёт порядка строк bottom-up и выравнивания строк до 4 байт (подробнее — ниже).
  • При сохранении — пересчёт bfSize и biSizeImage, запись padding’а в конце каждой строки.
  • Комментарии к неочевидным шагам: разбор заголовка, смещение до пикселей, padding.

Студент 2 — наложение водяного знака

  • Функция applyWatermark(base, mark) или метод класса, который смешивает два изображения, загруженных классом студента 1.
  • Если водяной знак меньше основного изображения — разместить его в выбранной области (правый нижний угол, центр) и менять только её; если больше — наложить по пересечению или вернуть ошибку.
  • Небольшие проверочные примеры: картинки 5×5 или 10×10, наложение белого, чёрного, самого на себя.
  • Своя ветка (например, watermark-feature) и слияние с кодом студента 1 без потери чужих изменений, лучше через Pull Request.

Студент 3 — интеграция, сборка, CI и README

  • Ревью кода студентов 1 и 2, исправления или замечания авторам.
  • main.cpp: пути к исходному изображению, водяному знаку и результату (через argv или ввод с консоли), загрузка, наложение, сохранение, сообщения о ходе работы.
  • Понятные ошибки: подсказка по использованию без аргументов, «Файл водяного знака не найден», «Размеры изображений не совпадают» и т. п. Программа не должна падать на несуществующем файле.
  • Сборка через CMake (или по согласованию с преподавателем), раскладка по папкам, .gitignore для сборочных файлов и бинарников.
  • Workflow GitHub Actions, тесты, бейдж статуса и README.md.

Формат BMP

Достаточно поддержать несжатый 24-битный BMP (Windows Bitmap v3 с заголовком BITMAPINFOHEADER):

ЧастьРазмерЧто внутри
BITMAPFILEHEADER14 байтсигнатура BM, размер файла, зарезервированные поля, смещение до пикселей bfOffBits
BITMAPINFOHEADER40 байтразмер структуры, ширина, высота, число плоскостей, бит на пиксель (24), сжатие (BI_RGB = 0), размер изображения (может быть 0), разрешение, число цветов
Пикселис bfOffBits (обычно 54)по 3 байта на пиксель в порядке B, G, R
Строки снизу вверх
При положительной высоте первой в файле идёт нижняя строка изображения. Удобнее всего при чтении сразу перевернуть строки в обычный порядок (сверху вниз), а при записи — обратно, иначе водяной знак окажется не там или результат будет перевёрнут.
Выравнивание строк
Каждая строка дополняется нулевыми байтами до длины, кратной 4. Для ширины 3 пикселя данные занимают 9 байт, к ним добавляются 3 байта padding’а — всего 12. При чтении эти байты пропускаются, при записи — дописываются: padding = (4 - width * 3 % 4) % 4.

Порядок байтов в BMP — little-endian, на x86 он совпадает с порядком в памяти, поэтому структуры можно читать напрямую.

Алгоритм наложения

Для каждого пикселя области водяного знака новый цвет — смесь исходного и цвета метки:

cnew=corig⋅(1−α)+cmark⋅αc_{\text{new}} = c_{\text{orig}} \cdot (1 - \alpha) + c_{\text{mark}} \cdot \alpha

При α=0.5\alpha = 0.5 это просто среднее: (orig + mark) / 2. Чтобы знак был прозрачнее, берут α=0.3\alpha = 0.3: 70% оригинала и 30% метки. Значение α\alpha и его выбор стоит объяснить в комментарии.

Переполнение
Сумма двух uint8_t не помещается в байт: 200 + 100 превратится в 44. Считайте в int (или float для α\alpha) и только в конце приводите результат обратно к uint8_t в диапазоне 0–255.

Проверки здравого смысла при α=0.5\alpha = 0.5: белый водяной знак осветляет картинку наполовину, чёрный — затемняет, изображение, наложенное само на себя, не меняется.

Git и GitHub

  • Один общий репозиторий на GitHub (например, bmp-watermark-project), у всех троих есть доступ: Collaborators или организация.
  • Работа в ветках по задачам (bmp-class-dev, watermark-feature, integration), слияние в основную ветку, по возможности через Pull Request с ревью.
  • Частые коммиты с осмысленными сообщениями. В истории должен быть виден вклад каждого: класс BMP — коммиты студента 1, наложение — студента 2, main, CI и README — студента 3.
Не одним коммитом
Весь код, добавленный одним коммитом от одного человека накануне дедлайна, — главная причина незачёта. Работа должна выглядеть и быть командной.

CI на GitHub Actions

Workflow (например, .github/workflows/ci.yml) запускается на push и pull_request в основную ветку, собирает проект на ubuntu-latest и гоняет тесты:

.github/workflows/ci.yml
name: CI
 
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
      - run: cmake --build build
      - run: ctest --test-dir build --output-on-failure

Без CMake шаг сборки может быть прямым вызовом компилятора, например g++ -std=c++17 -Wall -Wextra -O2 -o watermark main.cpp bmp.cpp watermark.cpp. После первого прогона скопируйте бейдж статуса из вкладки Actions в начало README.

Тесты

  • Тестовые изображения в репозитории (папка examples/ или tests/): original.bmp, watermark.bmp и ожидаемый expected.bmp.
  • Unit-тест смешивания: функция вроде blendPixel(orig, mark) на известных значениях.
  • Синтетический тест: в коде создать зелёное и красное изображения, наложить и проверить несколько пикселей результата.
  • Обратная проверка: сохранить результат, загрузить снова и убедиться, что размеры и заголовок верные, а пиксели изменились только в области наложения.

Порядок работы

  1. Создать репозиторий с README.md, сделать первый коммит и push, выдать доступ остальным.
  2. Вместе спланировать архитектуру: классы и функции, коэффициент α\alpha, позицию знака, тестовые файлы, порядок слияния веток.
  3. Студент 1 реализует и отлаживает чтение и запись BMP на маленьких картинках (2×2, 3×3), вливает в основную ветку.
  4. Студент 2 подтягивает класс, реализует наложение в своей ветке, проверяет на примерах и открывает Pull Request.
  5. Студент 3 делает ревью, пишет main, обработку ошибок, CMake, workflow и тесты, разрешает конфликты.
  6. Прогон на настоящих картинках: фотография и небольшой логотип, проверка результата в просмотрщике.
  7. README, финальный коммит, зелёный статус Actions.

Требования

  • Программа на C++17 или новее читает 24-битные BMP без сжатия и сохраняет результат в новый BMP, который открывается обычным просмотрщиком.
  • Разбор BMP написан самостоятельно, без библиотек для изображений; учтены порядок строк bottom-up и padding.
  • Наложение полупрозрачное: водяной знак виден, исходное изображение просматривается; нет переполнения при смешивании цветов.
  • Код разнесён по заголовкам и файлам реализации, функции короткие, неочевидные места прокомментированы, стиль именования единый.
  • Ошибки обрабатываются с понятными сообщениями: нет аргументов, файл не найден, неподдерживаемый формат, несовместимые размеры.
  • Сборка через CMake, Makefile или описанную команду; в репозитории нет сборочных файлов и бинарников (.gitignore).
  • Workflow GitHub Actions собирает проект и запускает тесты на push и pull_request, статус последнего коммита — зелёный.
  • В репозитории есть тестовые изображения и ожидаемый результат.
  • В истории Git — много осмысленных коммитов от каждого из трёх участников.
  • README.md описывает задачу, устройство решения, алгоритм смешивания, сборку и запуск с примером, тесты, состав команды и роли, результаты «до и после», возможные улучшения.

Как сдавать

Ссылка на публичный репозиторий на GitHub с зелёным статусом Actions. На защите — показать запуск программы, результат в просмотрщике, историю коммитов и Pull Request’ы; каждый участник рассказывает свою часть.

Материалы

Комментарии0

Пока никто ничего не написал.

Войдите, чтобы оставить комментарий