二維碼美化策略——QArt Codes

我們所知的二維碼有三類編碼標準:PDF417、DM以及我們日常見到使用最多的QRCode。本文介紹的是由作者Cox所提出來的一種針對於QRCode的美化策略,以下是全文部分:

QRcode是一種用來對字節符號進行編碼的二維碼。它的最常用方法之一便是在手機上替代網址的手動輸入,而採用掃描帶有網址信息的QRcode來打開相應的URL地址(常見的比如廣告海報,不常見的比如飛機後面的條幅[link],GEEK的比如谷歌地圖所看到的屋頂[link],2B的比如在自己衣服上褲子上[link][link]等等)

QRcode採用裏德-所羅門碼來進行編碼,裏德-所羅門碼是一種帶有容錯機制的編碼方法,採用這種機制掃描的時候並不需要讀取所有的比特位,因此也使得簡單的在QRcode中少量的更改信息,比如加入小型的圖片等等,成爲了可能。舉個例子,2008年的時候Duncan Robertson爲BBC電視臺製作了一幅QRcode圖片,就是用到了其強大的容錯能力。

這是一種很簡單但又非常實用的技巧,但是,站在技術的角度來看會感到很乏味。儘管上面的BBC三個大字看起來是很像一個QRcode裏的字節符,但它對於QRcode的解碼所帶來的,僅僅是錯誤信息的冗餘而已。我們可以把BBC三個字符處換成任何字符甚至圖片,他們之間的唯一區別僅僅是帶來的不同噪聲而已。

在這個BBC QR Logo出來之後,網上出現了相當多的模仿者,大部分和上面一樣,只是把中間的字符換成自己所喜愛的噪聲信號。比如這幅迪斯尼海報就是代表[link]。

其實要說的是,對於我們技術工作者來說,有其他更好的方法來製作包含自己圖像的QRcode,而不是僅僅添加一些無聊的噪聲,和依靠QRcode的容錯率來得到一個相對穩定的二維碼。就比如下面這些:

這篇文章所要解釋的就是製作這種二維碼背後所包含的數學原理,也包括其簡單的製作方法。文中所用到的源碼發佈在code.google.com/p/rsc上,並且還製作了一個在線的轉換網站[link]。

 

背景知識

QRcode使用裏德-所羅門碼來進行錯誤修正。對於我們來說,裏德-所羅門編碼有兩個非常重要的特性。第一,它是一種顯式系統碼,也就是說,你可以在最終的編碼中直接看到原有的信息。就好比我們對」hello world」進行編碼,最終看到的是」hello world」以及其後面跟隨的幾個容錯碼。第二點,裏德-所羅門編碼是可以被」異或」的,將兩個不同裏德-所羅門編碼得到的結果異或運算後會得到一個新的裏德-所羅門碼,並且這個新碼的原碼即是原來兩個原碼的異或。如果你想知道爲什麼這兩個特性會成立,請看我更早的一篇文章Finite Field Arithmetic and Reed-Solomon Coding.

QRcode

一副QRcode圖像會定義一些獨特的描述符來幫助人們或者電腦識別出自己是一張QRcode。這種描述符隨着QRcode的大小不同而略有區別——越大的QRcode圖像擁有越多的描述符。但是對於人的識別來說,特徵最明顯的還是圖片的四個角的符號是固定的,看到這樣的四個角人類就本能的反應:這是一個QRcode。下面就是一些示例描述符。

上圖中彩色部分就是編好的裏德-所羅門碼。對於每一副圖像來說,可能含有一塊或者多塊裏德-所羅門編碼塊,這個是由圖像大小以及設定的糾錯能力來決定的。對於下圖來說,不同的編碼塊對應不同的顏色,L編碼方式對應最小的錯誤冗餘,爲20%,其餘的三種則分別增加冗餘碼,對應的百分比爲38%,55%,和65%。

(實際上,我們可以通過讀取圖像最左上角的兩個象素點來判斷編碼的冗餘程度。定義黑色爲0,白色爲1,那麼如果看到00則是L級別的冗餘,01是M,10是Q,11則是最高的H級別冗餘。現在,我們可以通過這種方法判斷這幅印在T恤上的QR碼[link]知道它所用的是最高級別的冗餘,而另外的一件[link]比較2B的則用的是最少的冗餘,以至於難以甚至無法讀取)

正如我上面所提到的一樣,原碼信息是被顯式的包含在被編碼的圖像中的,這樣,原碼信息中的每一個比特就與QR圖像中的每一個像素所對應。這些像素在上面的圖像中對應非灰色的色彩部分,灰色部分則是用於糾錯的冗餘信息碼。編碼好的比特是按照Z字形的結構連續排列在圖像中的每一個像素上,從左下角開始並在右下角結束,如下圖:

有了上面的這些工作,我們可以非常容易的知道原碼信息在圖像中的位置。然後通過改變自己的原碼信息,就可以改變圖像中的像素以至於可以在裏面作圖了。雖說如此,下面的一些情形可以讓事情變得更有趣。

QR Masks

第一個難點就是編碼完成的數據會按照下面的幾個模板來異或運算進行混淆,混淆過後纔是最終得到的圖像。這樣的模板有8個

對於一個QR編碼器來說,它會根據輸入的數據情況來選擇最合適的模板來進行混淆,使得原本的數據隱藏起來。但在我們的這個編碼器中,我們可以先選擇好模板,然後再決定設計輸入的數據。雖然說與原本的設計模式相違背,但依然可以產生合法的代碼。

QR Code編碼

第二個難點就是我們想要製作的是含有容易理解的信息的QRcode。簡單來說你可以隨意的按照自己設計的圖片來生成QRcode,但這樣解碼出來的數據就完全是雜亂無章的亂碼,作爲一副QR圖像來說就毫無意義了。因此我們需要約束自己的圖案,以求產生包含能理解的內容的QRcode。幸運的是,QRcode允許原碼信息以一些符號來表示,其中一種是一個8比特的數據,它需要引入一些垃圾數據來生成一副圖像。另一種則是數值數據,這種格式中每10個比特表示3個十進制字符。到這裏,製作特定圖像中的限制已經很明顯了,我們不能生成值超過999的10比特數據(注:10比特二進制最大值爲1023)。儘管不能完全按照我們想要的來,但其靈活性已經很高了,能使用的比特串達到所有比特串的99.6%。因此,在生成自己想要的圖片後,如果發現解碼錯誤,我們隨機選5個最具代表性的值爲1的比特位——只有1才能產生錯誤的比特碼——然後直接改寫成0,重複掃描和以上的步驟。

但是僅僅有數字數據並不是一件有趣的事,我們掃描QR碼只能得到一個毫無意義的巨大的十進制數值。又一次幸運的是,QRcode允許在一條信息中採用多種不同的編碼類型。因此我就製作了這樣的一條信息,前面一部分是自己的網址信息,然後再在一個#符號後面插入用來作圖的數值數據。

http://swtch.com/pjw/#123456789…

數據前面的URL最先被編碼,它在QR圖像中佔據最左邊的部分,然後整個數據的冗餘被加到編碼數據的尾部,它佔據了QR圖像最右邊的部分。中間的部分就是我們自己預先設定好的圖像比特數據。

當使用手機掃描這幅QR圖像的時候,解碼器識別出URL並在瀏覽器中打開這個地址,然後根據其後#處的數值跳到頁面相應的遊標處。當然,這樣的遊標是不存在的,即便這樣瀏覽器也不會發出任何抱怨。

使用這樣的方法產生的圖像如下:

後面的那張圖將我們所不能控制的象素點用灰色表現了出來:左邊的URL數據信息和右邊的冗餘碼信息。我很欣賞這種人物的一部分融入噪聲狀冗餘信號所產生出來的終結者(斯瓦辛格電影中的未來機器人)效果,但如果進一步擴大目前的視野會更好。

高斯-約旦消元

製作過程的第三個難點是,如何才能將想要的圖像均勻的平鋪在QRcode中,而不是前面的那種僅僅顯示在中間的一小塊。再次幸運的是,這一點我們仍然可以做到。

我之前提到過裏德-所羅門碼是一種可以被異或的編碼方法:如果兩個不同的裏德-所羅門碼塊b1和b2,它們的原碼信息分別爲m1和m2,那麼b1⊕b2依然是裏德-所羅門碼,並且這個合成碼的原碼會變爲m1⊕m2(原因在我前面的這篇文章[link]中有解釋)。這個特性讓我們可以從一個合法的QRcode中產生另一個合法的QRcode。特別的,我們構建以下比特序列b0,b1,b2…,其中的bi就是指一個除開第i位之外其它位置都是0的比特塊,然後尾部跟上冗餘碼以構成一個合法的裏德-所羅門編碼。這一組序列就是整個裏德-所羅門碼空間的一組基向量。下圖所示矩陣就是2數據位2冗餘位的基向量序列

沒有填寫的部分都代表比特位爲0。灰色部分就是我們可以自己完全控制的比特部分,白色部分則是尾隨後面的糾錯冗餘碼。由上面的異或特性我們知道,我們可以將編完碼的結果和上面的這組基進行異或,而不改變其他的控制位,並且保持冗餘碼的更新。

可能你又要抱怨了,這種做法其實無所事事,我們的圖像位置該在哪兒還是在哪兒,沒起到作用。

請等我慢慢說完,在有了上面知識的基礎上,我們可以通過把多個基組合起來,以達到將自己的數據和容錯碼中的數據交換的目的。雖然說在根本上我們不能增加可以自由控制的點的數目,但卻可以移動可以自由控制的點的位置——也就是說達到將不可控點空間分散化的效果,將這些不合作的控制點對圖像整體的影響降低。這其實就是小標題中高斯-約旦消元法的基本思想,從原矩陣中產生一個簡化的行列式。

上面的這個矩陣給了我們一個重要提示,即是沒法做到完全一般化。儘管這些比特串是完全相互獨立的,但是由於同時還需要照顧不守規矩的錯誤冗餘碼,我們沒法做到QR圖像中的每一個像素都是我們想要的值。在這裏例子中,比特串最後的四個比特是不可控的,我們所做的操作就是通過上述基來對比特位置重構,分散不可控的點,使最終畫面更協調。

在實際的程序裏,採用這種思想的一個做法便是對裏德-所羅門碼塊中的每一個比特,根據其在圖像中的重要性進行打分與排序(圖像中高對比區域像素的得分小於低對比區域像素),然後遍歷圖像中每一個像素,如果我們的基允許對其的改變並且改變後的得分更高的話,那麼用相應的基對他進行異或,否則繼續處理下一個像素。

使用這種方法,我們可以得到更寬但噪聲更多的QR圖像

圖片裏所示人物的前額以及右半部分的臉就爲得到更寬的腦袋而犧牲了。

我們還可以隨機決定可控點的位置,然後產生一種霧化的圖片效果

旋轉

好了,以上方法介紹完畢之後大家都可以製作差不多湊合的QR圖像了。我這裏還剩下處理的最後一招,就是QR圖像的旋轉。在上面的圖像裏所有沒法控制的冗餘點部分都存在於存在於QR圖像的右側,但由於QRcode對於圖像的旋轉沒有任何要求,因此其實可以把這部分移動到別的什麼地方。

 

其他

關於這篇文章所使用的代碼,可以在 code.google.com/p/rsc/source/browse/qr上找到。如果你喜歡這篇文章,我猜你也可能同時喜歡我的另一篇Zip Files All The Way Down

鳴謝

Alex Healy指出了裏德-所羅門碼對於異或運算是封閉的,這個是將冗餘碼分散到整幅圖像中的關鍵。Peter Weinberger什麼也沒做,但很慷慨的爲我們提供了演示所用的圖像。在這裏感謝他們二位

譯文轉自:https://blog.csdn.net/yanlaizhishi/article/details/8522722

原文來自:https://research.swtch.com/qart