Вообще qr-кодов есть несколько разновидностей. Можно выделить несколько этапов чтения типичного QR-кода.
0) Компьютер выхватывает изображение qr-кода, накладывает на него трафарет-клеточку, и на основании яркости каждой клеточки заполняет у себя в памяти массив из бит, который, в идеале, является отображением реального qr-кода.
1) Проверка изображения на то что оно - qr-код. Именно для этого на всех qr-кодах есть характерные квадраты - они нужны, чтобы компьютер "зацепился".
2) Дальше электронный глаз должен прочитать системную информацию, которая хранится в определенных регионах QR-кода. Зоны между квадратами и контур толщиной два бита внутри получившейся Г-образной фигуры отданы под системную информацию.
3) На основании полученной информации извлекаются данные об избыточности кода и маска.
4) Маска "кладётся" сверху на QR-код. Она представляет из себя еще один набор битов, точно соответствующий по размеру самому QR-коду, с достаточно правильным рисунком, который определяется отдельным математическим выражением, но мы для простоты будем считать, что это есть фиксированный набор масок и мы выбираем одну из них в соответствии с системной информацией. В зависимости от того, какое значение у бита маски, соответствующий бит QR-кода меняет значение на противоположное, или остается неизменным.
5) Идем в угол который не занят ни одним из калибровочных квадратов. Договоримся, что он нижний правый. Зона шириной в два бита по правой бровке QR-кода содержит заголовок и немного данных. Читаем справа-налево, снизу-вверх с учетом маски. Получаем код, указывающий на тип данных. Он может быть буквенный, числовой, иероглифами кандзи и еще некоторыми типами.
6) Продолжаем идти по заголовку читаем, в зависимости от типа данных следующие несколько бит (обычно около 8, зависит от типа данных), с помощью маски получаем из них двоичное число - количество задействанных блоков, размер которых также определяется типом данных.
7) После этого мы продолжаем идти по бровке и записывать полученные биты, пока не будет считано (длина блока*количество блоков) битов. Если вдруг мы дошли до части с системной информацией, то значит первый столбец закончился. Нам надо взять более левый столбик шириной два бита и читать его слева направо сверху вниз. Если нам и этого столбика не будет достаточно, то нужно взять следующий столбик - еще левее и работать с ним аналогично первому. Надеюсь принцип понятен.
8) Полученную последовательность делим согласно количеству бит и преобразовываем согласно таблице или иным способом в результирующие символы.
Это сжатое описание процесса, более полный текст, с картинками вот тут:
https://geektimes.ru/post/256932/
Более предметно ознакомиться с реализацией таких алгоритмов можно на примере библиотек с открытым кодом, которые, как раз, используются разработчиками готовых приложений: