기획 기사 기획 기사

공대생 삼 년이면 QR코드를 읽는다

글. 화학생물공학부 2 최준성 편집. 기계공학부 4 정윤종
“삐빅! 인증되었습니다.” 여느 때처럼 집에서 조금 일찍 나와 근처 카페에서 음료를 주문하던 중이었습니다. 평소였다면 카페 안을 스윽 둘러보고는 진동벨을 받아 자리잡았겠지만, 어찌된 탓인지 QR코드로 된 전자출입명부가 눈에 딱 꽂히는 게 아니겠어요? 검정색 네모 옆에 하얀색 네모… QR코드 속 네모들을 홀린 듯이 바라보다가 문득 괴짜 같은 생각이 머리를 스쳤습니다. ‘저걸 스캐너 없이 손수 해독할 수는 없을까?’
그림 1. 21X21픽셀1 QR 코드

가장 간단한 형태인 가로 세로 21픽셀1 크기의 QR코드부터 살펴보겠습니다. 무엇이 가장 먼저 눈에 들어오시나요? 저에게는 세 개의 큰 눈동자 모양 사각형들이 보이는데요, 이들은 스캐너가 코드를 올바른 방향으로 읽을 수 있도록 하는 기준점 역할을 합니다. 기준점이 총 3개 존재하기 때문에 QR코드가 회전하더라도 매번 일정한 방향으로 코드를 읽어낼 수 있는 것이지요.

그림 2. 세 개의 눈동자 모양

다음으로 살펴보아야 할 부분은 눈동자 ①의 바로 아랫줄과, 눈동자 ③의 바로 오른쪽 줄의 7 픽셀입니다. [그림 3]을 보면 이들 7 픽셀(노란색)이 서로 완전히 동일한 것을 알 수 있는데, 이는 우연이 아니라 항상 같은 모양을 갖도록 설계된 것입니다. 7개의 픽셀 중, 앞쪽 두 픽셀은 오류 수정 정도를, 뒤쪽 두 픽셀은 오류 수정 포맷을 알려줍니다. 이들은 QR코드가 훼손되었을 때에도 코드를 잘 읽을 수 있도록 도와주는 부분인 것이지요.

1화소, 디지털 화면을 구성하는 기본 단위로 사각형 모양의 점이다.

그림 3. 쌍둥이 7 픽셀

일곱 개의 픽셀에서 앞서 말한 양쪽 끝 두 픽셀을 제외하고 보면, 가운데 세 개의 픽셀들이 남습니다. 이들은 QR코드의 마스킹2 패턴을 알려주는데, 마스킹은 QR코드를 인식할 때 오류를 줄여주는 기능을 합니다. 만약 암호화된 정보가 QR코드 위에서 눈동자 배열과 유사하거나, 같은 색의 픽셀들이 뭉쳐 덩어리를 이루면 어떻게 될까요? 스캐너가 기준점을 잘 못 잡고, 뭉쳐 있는 부분의 픽셀 수를 빨리 인식하지 못해 코드의 성능이 떨어질 것입니다. QR코드에 적절한 마스킹 패턴을 이용함으로써 이러한 문제를 방지할 수 있습니다.

이제 우리는 마스킹 작업이 코드의 어디서부터 어디까지 이루어지는지 알아야 합니다. 놀랍게도 눈동자 모양과 한 쌍의 7 픽셀을 제외한 QR 코드 모든 영역이 마스킹 대상이 됩니다. [그림 3]의 색칠되지 않은 흑백 영역이 모두 마스킹 되는 것이지요. 그렇다면, 마스킹 패턴은 마스킹 영역에 어떤 식으로 영향을 주는 것일까요?

코드 위에 마스킹 패턴을 겹쳐 놓았을 때, 2개 픽셀의 색이 같으면 0(흰색)으로, 색이 서로 다르면 1(검정색)로 픽셀의 색을 바꾼다.


예시를 들어볼까요? 0100을 1110 패턴으로 마스킹한다고 생각해봅시다. 첫번째와 세번째 자리는 서로 색이 다르므로 1이 되고, 두번째와 네번째 자리는 서로 색이 같아 0이 됩니다. 결국 마스킹한 결과는 1010이 되는 것이지요.

그림 4. 마스킹 과정

코드 속 메시지에 따라 어떤 픽셀 패턴이 등장할지 알 수 없기 때문에, QR코드의 마스킹 패턴은 8종류나 있습니다. 8개의 마스킹 패턴 중 코드의 인식을 방해하는 픽셀 배열이 가장 적은 마스크를 골라서 코드의 인식 속도와 정확도를 향상시키는 것입니다.

2비트 연산의 일종으로, 0과 1로 구성된 이진 정보를 숨기거나 변형시키기 위해 사용한다.

그림 5. 8가지 마스킹 패턴

예시 코드에서 마스킹 패턴을 가리키는 배열이 101이므로, 이 경우에는 [그림 4]의 3번째에 있는 체크모양 패턴으로 코드를 마스킹 해야 합니다. 그런데 마스킹이 필요한 영역을 전부 덮기에는 그림 속 패턴이 너무 작지요? 이는 그림 속 패턴들이 전체 마스킹 패턴에서 반복되는 일부만을 보여주고 있기 때문입니다. QR코드의 왼쪽 위 구석에 맞추어 그림의 마스킹 패턴들을 차곡차곡 쌓아 나가면 전체 마스킹 패턴을 얻어낼 수 있습니다. 여러 모양의 타일 중 하나를 골라 화장실 바닥에 까는 상황을 상상하면 이해가 쉽습니다. 마스킹 패턴이 완성됐다면 이 패턴으로 마스킹을 한 번 진행해봅시다!

어때요, 이제 코드가 좀 볼만 한가요? 사실 코드 속 정보들을 우리의 언어로 바꾸기 위해서는 한 차례 복호화3 과정이 더 필요합니다. 인코딩 포맷에 관한 정보는 코드의 오른쪽 아래에 위치해 있고, 가로 세로 두 픽셀, 총 4bit 크기로 저장되어 있습니다. 인코딩 포맷도 마스킹 패턴과 마찬가지로 총 8종류가 있는데, 그중에서도 우리가 알아볼 포맷은 0010으로 부호화 되는 Alphanumeric 인코딩4 과 0100으로 부호화 되는 Byte 인코딩5 입니다.

3디코딩, 부호화 된 정보를 다시 원래의 언어로 되돌리는 과정 32호 일상 속 공학 찾기, 확장자.mp3의 비밀 참조.
4웹주소에 자주 사용되는 알파벳 대문자, 숫자, 몇 가지 특수기호를 포함한 set을 부호화 하는 인코딩 방식, set의 크기가 작은 만큼 글자당 평균 5.5bit를 사용한다.
5alphanumeric 인코딩이 지원하지 않는 알파벳 소문자, 거의 모든 특수기호까지 지원하는 표준적인 인코딩 방식, 글자당 8bit를 사용하므로 Byte 인코딩이라고 불린다.

그림 6. 마스킹이 완료된 예시 코드

Alphanumeric 인코딩에서는 먼저 메시지 전체 길이를 이진수로 바꾼 뒤, 코드의 첫 9개 픽셀에 이를 기록합니다. 이어서 코드 속 메시지를 두 문자씩 묶어 11 픽셀 공간에 이를 기록합니다. 해당 인코딩 포맷에서는 두 문자를 길이 11의 이진수로 바꾸기 위해 특별한 방법을 사용합니다. 먼저 [그림 7]의 표처럼 0부터 44까지의 숫자들에 각각 하나의 문자를 대응시킵니다. 그리고는 첫번째 문자에 대응하는 숫자에 45를 곱하고, 두번째 문자에 대응하는 숫자를 여기에 더해 십진수를 얻어냅니다. 이를 다시 이진수로 바꾼 값을 11개의 픽셀에 기록하는 것입니다. Byte 인코딩도 거의 비슷합니다. 대신 Byte 인코딩에서는 메시지 전체의 길이를 8 픽셀에 기록하고, 한 글자당 8픽셀씩 할당하여 기록하며, ASCII6 를 기반으로 한다는 점이 다릅니다.

그림 7. Alphanumeric 인코딩

인코딩 포맷을 이용해 코드의 해석을 시작하기 전에, 마지막으로 알아야 할 것이 한 가지 남았습니다! 바로 코드를 읽는 순서와 방향입니다. QR 코드는 오른쪽 아래 귀퉁이부터 시작해 두 줄씩 묶어 위 아래 지그재그 방향으로, 오른쪽에서 왼쪽 픽셀 순서로 읽어 나가도록 설계되어 있습니다. [그림 7]에서 나타난 파란색과 빨간색 화살표들을 보면서, 예시 코드의 첫 4bit가 어떻게 0010으로 읽히는지 생각해보면 금방 이해할 수 있을 것입니다.

6미국정보교환표준부호, 영문 알파벳을 사용하는 대표적인 문자 인코딩 방식으로, 본문의 Byte 인코딩도 ASCII의 ISO/IEC 8859-1:1998를 기반으로 한다. 35호 공학, 문자와 만나다 참조.

그림 8. 코드를 읽는 순서

이제 예시 코드에 배운 것들을 한데 모아 적용시켜볼까요? 예시 코드를 올바르게 읽었다면, 첫 4bit가 0010일 것입니다. 이는 이 코드를 Alphanumeric 인코딩으로 부호화 시켰음을 의미합니다. 또, 뒤따르는 9bit 000001000을 십진법으로 바꾼 값이 8이므로, 코드 속 메시지의 길이는 8입니다. 뒤를 이어서 나오는 11bit가 01011101000인데, 코드 속 실제 메시지는 여기서부터 시작합니다.

이 11bit를 십진법으로 바꾸면 744이고, 이 값을 45로 나눈 몫은 16이고 나머지는 24입니다. [그림 7]에서 16은 ‘G’, 24는 ‘O’를 가리키므로 코드에 저장된 메세지의 앞 두 글자는 ‘GO’가 되겠네요. 아직은 조금 헷갈리시나요? 한 번만 더 보여드리겠습니다! ‘GO’로 읽히는 부분 뒤의 11bit는 10000011011, 십진법으로는 1051이지요? 1051을 45로 나눈 몫은 23 나머지는 16이므로, ‘GO’에 잇따르는 두 글자는 “NG”가 되는 것입니다. ‘GONG’! 벌써 메시지의 반이나 해석했네요. 이제 차근차근 코드의 나머지 부분도 끊어서 해석해볼까요? 두구두구, 코드 속에 숨겨진 메시지는 바로 “GONGSANG”이었습니다!

그림 8. 코드 속 메시지 “GONGSANG”

그러면 이제 더 복잡한 QR코드에 대해서도 한번 도전해볼까요? 이번에 가져온 예시 코드는 가로 세로 29짜리 QR코드입니다. 먼저 마스킹 작업부터 시작해봅시다. 마스킹 패턴을 알려주는 배열이 111이므로, [그림 5]의 10시 방향에 있는 평행한 수직선 모양의 마스킹 패턴을 사용해야합니다.

그림 10. 마스킹 Before & After

또 인코딩 포맷을 알려주는 배열은 0100이므로 Byte인코딩을 사용할 준비를 합시다. 이 코드의 첫 8bit는 00110010로, 코드 속 메시지의 길이는 50이 됩니다. 뒤따르는 코드들도 마찬가지로 8bit씩 끊어서 읽어보면, 01101000 01110100 01110100 01110000…이 되겠네요. 이제 ASCII 표를 바탕으로 한 글자씩 대응시키기만 하면 메시지를 완성할 수 있습니다. 첫 글자는 h, 그 다음 글자는 t, 그리고 t와 p… 여러분들은 코드에 담긴 메시지를 알아내셨나요? 정답은 바로바로 새 단장한 공대상상지의 웹 주소인 http://beengineers.snu-eng.kr/html/2108/였습니다! 링크를 타고 2021년 가을호에는 어떠한 신기한 공학기사들이 있는지 확인해볼까요?

정보출처
그림출처
그림 5. https://en.wikipedia.org/wiki/QR_code#/media/File:QR_Format_Information.svg