現(xiàn)與相關(guān)性分析)
做圖像加密解密實(shí)驗(yàn)時(shí)Halton序列是個(gè)容易被忽略但非常好用的工具。最近我把自己那套基于Halton序列做位置擾亂和像素?cái)_亂、附帶相關(guān)性分析的Matlab GUI項(xiàng)目完整梳理了一遍從算法設(shè)計(jì)到界面回調(diào)再到最后的指標(biāo)驗(yàn)證踩了不少坑也攢了不少經(jīng)驗(yàn)。這篇文章就圍繞這個(gè)項(xiàng)目展開把能直接復(fù)用的代碼邏輯、參數(shù)設(shè)定和調(diào)試順序都寫清楚給正在做圖像安全、圖像置亂或Matlab圖像處理的朋友一個(gè)參考。1. 為什么會(huì)用Halton序列來做圖像加密1.1 圖像加密常用的置亂與擴(kuò)散套路圖像加密和普通文本加密有個(gè)很大的區(qū)別圖像數(shù)據(jù)量大、相鄰像素高度相關(guān)如果直接把整張圖片當(dāng)成一段二進(jìn)制數(shù)據(jù)塞進(jìn)AES這類分組加密算法里計(jì)算開銷非常大而且加密后的密文仍然會(huì)在像素級(jí)別保留一部分局部特征。所以在實(shí)際項(xiàng)目中大家更傾向于先做“置亂”再做“擴(kuò)散”也就是先打亂像素的位置再改變像素的值。置亂的經(jīng)典方案很多比如Arnold變換貓臉變換、Logistic混沌序列映射、基于隨機(jī)置換表的重排。這些方法各有各的特點(diǎn)Arnold變換適合方形圖像而且具有周期性周期到了圖像會(huì)自己還原好處是逆過程好寫壞處是密鑰空間相對(duì)有限Logistic混沌序列對(duì)初始值非常敏感但很多實(shí)現(xiàn)里序列分布并不均勻容易出現(xiàn)局部聚集導(dǎo)致加密后的圖像在某些區(qū)域殘留紋理。擴(kuò)散部分的常見做法是生成一串與圖像像素等長(zhǎng)的密鑰流然后做異或、模加或模減。密鑰流來源可以是偽隨機(jī)數(shù)發(fā)生器也可以是混沌系統(tǒng)。偽隨機(jī)數(shù)的優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單但它的可預(yù)測(cè)性取決于隨機(jī)種子如果種子被猜出來整串密鑰流都能還原。Halton序列給我的感覺是它既保留了“看似隨機(jī)”的分布特性又具備嚴(yán)格可復(fù)現(xiàn)、均勻性強(qiáng)的優(yōu)點(diǎn)很適合作為置亂和擴(kuò)散的統(tǒng)一“調(diào)度器”。1.2 Halton序列的特殊之處和選型理由Halton序列屬于低差異序列也叫準(zhǔn)隨機(jī)序列它和rand函數(shù)生成偽隨機(jī)數(shù)不一樣。偽隨機(jī)數(shù)追求的是統(tǒng)計(jì)獨(dú)立性但會(huì)出現(xiàn)明顯的聚集效應(yīng)Halton序列則追求在單位空間里盡量均勻地覆蓋不會(huì)扎堆。Halton序列的生成原理是選定一個(gè)基數(shù)通常用素?cái)?shù)把自然數(shù)n反復(fù)除以基數(shù)取小數(shù)部分再按位反轉(zhuǎn)。用公式表達(dá)就是function h halton_value(n, base) % 計(jì)算第 n 個(gè) Halton 序列值n 從 1 開始計(jì)數(shù) % 例如 halton_value(1, 2) 返回 0.5halton_value(2, 2) 返回 0.25 h 0; f 1 / base; i n; while i 0 h h f * mod(i, base); i floor(i / base); f f / base; end end這個(gè)序列天然產(chǎn)生在0到1之間而且不需要額外的隨機(jī)種子。只要給定基數(shù)和起始序號(hào)任何人都能重新生成完全一致的序列。對(duì)圖像加密來說這既是優(yōu)點(diǎn)也是特性它讓加密過程完全受參數(shù)控制整個(gè)密鑰就是“基數(shù) 起始序號(hào) 迭代輪數(shù)”這些可控量。我當(dāng)時(shí)選擇它還有一個(gè)很具體的原因用Halton序列生成置亂索引時(shí)序列的均勻分布會(huì)直接讓打亂后的像素在整幅圖里均勻分散。相比之下用randperm雖然也是隨機(jī)排列但排列本身的“隨機(jī)性”沒有結(jié)構(gòu)一旦某次實(shí)驗(yàn)的分布不夠理想加密結(jié)果里就會(huì)出現(xiàn)局部規(guī)律。Halton序列因?yàn)椴町惖?、覆蓋均勻幾乎不會(huì)出現(xiàn)這種問題。1.3 搭建“位置擾亂 像素?cái)_亂”的雙重加密鏈路這套項(xiàng)目的核心結(jié)構(gòu)其實(shí)非常簡(jiǎn)單先對(duì)圖像做位置擾亂再對(duì)置亂后的圖像做像素?cái)_亂。位置擾亂負(fù)責(zé)打亂空間結(jié)構(gòu)把“人臉的輪廓”拆成無意義的小碎塊像素?cái)_亂負(fù)責(zé)改變像素值讓碎塊的顏色、灰度分布也徹底改變。兩者缺一不可。如果只做位置擾亂加密后的圖像雖然看不出原圖內(nèi)容但直方圖依然保留原始統(tǒng)計(jì)特征攻擊者可以通過統(tǒng)計(jì)攻擊還原如果只做像素?cái)_亂圖像直方圖雖然均勻了但相鄰像素的空間位置還是連續(xù)的肉眼仍能看到物體輪廓。所以正確的順序一定是“先位置后像素”解密時(shí)反過來“先逆像素后逆位置”。這個(gè)順序在GUI代碼里也要嚴(yán)格對(duì)應(yīng)否則解密結(jié)果一定出錯(cuò)。整條鏈路的參數(shù)都可以作為密鑰位置擾亂用哪個(gè)基數(shù)、像素?cái)_亂用哪個(gè)基數(shù)、起始序號(hào)是幾、有沒有加反饋項(xiàng)、反饋初始值是什么。把這些組合起來密鑰空間足夠撐起一個(gè)教學(xué)演示或中等安全需求的項(xiàng)目。2. 加密鏈路的算法設(shè)計(jì)與參數(shù)確定2.1 位置擾亂用Halton排序生成坐標(biāo)置亂表位置擾亂這一步我采用的是“序列排序映射法”。具體思路是圖像有L個(gè)像素就生成L個(gè)Halton序列值每個(gè)值對(duì)應(yīng)一個(gè)原始像素序號(hào)然后對(duì)這些序列值排序排序后得到的索引順序就是置亂表。用代碼表示% 讀取灰度圖像 img imread(lena.png); [M, N] size(img); L M * N; % 生成基數(shù)為2的Halton序列長(zhǎng)度等于像素?cái)?shù) halton_seq arrayfun((i) halton_value(i, 2), 1:L); % 排序idx即為置亂目標(biāo)位置映射 [~, idx] sort(halton_seq); % 把圖像展成一行 img_vec img(:); % 置亂原始第i個(gè)像素移動(dòng)到第idx(i)個(gè)位置 shuffled_vec zeros(L, 1); for i 1:L shuffled_vec(idx(i)) img_vec(i); end shuffled_img reshape(shuffled_vec, M, N);這里要特別提醒一點(diǎn)shuffled_vec(idx(i)) img_vec(i);和shuffled_vec(i) img_vec(idx(i));作用完全不同。前者是把原圖的第i個(gè)像素放到目標(biāo)位置idx(i)后者是取出原圖idx(i)處的像素放到當(dāng)前位置。加密用前者解密就必須用后者的逆操作。我一開始就是因?yàn)檫@兩個(gè)方向沒拎清楚解密出來一直在“半加密”狀態(tài)。為什么不直接用隨機(jī)數(shù)當(dāng)映射因?yàn)殡S機(jī)數(shù)的排序結(jié)果雖然也是置換但無法控制分布質(zhì)量。Halton序列則不同它保證排序后的索引在空間上不聚集加密后的密文圖像不會(huì)在某個(gè)區(qū)域集中出現(xiàn)原圖像素這對(duì)抗裁剪攻擊更有價(jià)值。2.2 像素?cái)_亂Halton密鑰流加模運(yùn)算擴(kuò)散位置擾亂結(jié)束后圖像變成了“像素位置全被打亂”的狀態(tài)但每個(gè)像素值仍然是原值直方圖沒有變。這時(shí)就需要像素?cái)_亂來改變像素值。我的做法是再生成一組基數(shù)不同的Halton序列比如基數(shù)用3然后量化到0到255之間% 生成基數(shù)3的Halton序列長(zhǎng)度仍為L(zhǎng) halton_seq2 arrayfun((i) halton_value(i, 3), 1:L); % 量化到[0, 255] key_stream floor(halton_seq2 * 256); % 轉(zhuǎn)成uint8便于異或 key_stream uint8(key_stream); % 置亂圖像轉(zhuǎn)為uint8向量 shuffled_vec uint8(shuffled_vec); % 基礎(chǔ)版直接異或 encrypted_vec bitxor(shuffled_vec, key_stream); encrypted_img reshape(encrypted_vec, M, N);如果只做“異或”這一層解密非常簡(jiǎn)單同樣生成key_stream再異或一次就能還原置亂圖像。但這種模式有一個(gè)缺陷——密鑰流和像素逐一對(duì)應(yīng)如果兩個(gè)明文字節(jié)相同密文字節(jié)也相同容易被差分分析抓住規(guī)律。所以我更推薦帶反饋的擴(kuò)散結(jié)構(gòu)encrypted_vec zeros(L, 1); c_prev 173; % 反饋初始值可作為密鑰 for i 1:L encrypted_vec(i) bitxor(bitxor(double(shuffled_vec(i)), double(key_stream(i))), c_prev); c_prev encrypted_vec(i); end反饋項(xiàng)相當(dāng)于把前一個(gè)密文的狀態(tài)引入當(dāng)前像素形成一條“加密鏈”。這樣一來任何一個(gè)像素變化都會(huì)向后傳遞加密圖中相鄰位置的規(guī)律被徹底打散。2.3 解密流程與逆操作實(shí)現(xiàn)解密必須嚴(yán)格逆序先解像素?cái)_亂再解位置擾亂。帶反饋的像素?cái)_亂不能用正序循環(huán)因?yàn)楫?dāng)前狀態(tài)依賴前一個(gè)密文正序解會(huì)越解越亂。正確做法是從最后一個(gè)像素開始倒推或者按正序但每次都恢復(fù)c_prev。dec_vec zeros(L, 1); c_prev 173; for i 1:L % 先算當(dāng)前反饋鏈上的c_prev temp bitxor(encrypted_vec(i), c_prev); % 再剝掉密鑰流 dec_vec(i) bitxor(temp, double(key_stream(i))); c_prev encrypted_vec(i); end像素值還原后還要做位置逆擾亂。位置擾亂時(shí)是“原圖第i個(gè)像素移動(dòng)到idx(i)”那解密時(shí)只需要把reverse_idx定義出來reverse_idx(idx) 1:L; recovered_vec dec_vec(reverse_idx); recovered_img reshape(recovered_vec, M, N);這一步用向量化寫法更好循環(huán)寫法容易因?yàn)樗饕x值方向搞錯(cuò)而出bug。2.4 密鑰構(gòu)成與參數(shù)選擇建議通過上面的算法可以看出這套加密方法的密鑰并不復(fù)雜但組合起來已經(jīng)有一定的空間參數(shù)含義取值范圍建議base_pos位置擾亂使用的Halton基數(shù)素?cái)?shù)如2、3、5base_pix像素?cái)_亂使用的Halton基數(shù)與base_pos不同的素?cái)?shù)start_idxHalton序列起始序號(hào)任意正整數(shù)如1或100c_init反饋擴(kuò)散初始值0到255的整數(shù)rounds加密總輪數(shù)1到3輪2輪性價(jià)比最高我實(shí)測(cè)下來位置擾亂用基數(shù)2、像素?cái)_亂用基數(shù)3、反饋初始值取一個(gè)隨機(jī)數(shù)、加密輪數(shù)取2輪效果已經(jīng)很穩(wěn)定。輪數(shù)超過3之后視覺上區(qū)別不大但計(jì)算時(shí)間成倍增加尤其GUI界面上會(huì)明顯卡頓反而不適合做演示。有一點(diǎn)要提醒Halton序列的值分布雖然均勻但序列開頭部分不一定是最理想的密鑰流所以start_idx可以設(shè)置成100、1000之類的偏移量。這個(gè)偏移量同樣起到密鑰作用外部攻擊者如果不知道偏移量即使猜到基數(shù)也沒法恢復(fù)圖像。3. Matlab GUI的實(shí)現(xiàn)細(xì)節(jié)和源碼使用說明3.1 GUI布局從需求到控件安排我的GUI項(xiàng)目是基于Matlab App Designer寫的因?yàn)樾掳姹緦?duì)App Designer支持得最好代碼維護(hù)也方便。界面布局要對(duì)應(yīng)功能流程我建議從上到下、從左到右安排第一行是圖像讀取區(qū)第二行是加密解密操作按鈕第三行是三個(gè)坐標(biāo)軸用來顯示原圖、密文圖、解密圖第四行放參數(shù)輸入框和相關(guān)性分析按鈕??丶荜P(guān)鍵我習(xí)慣給每個(gè)控件加清晰的前綴比如Button_Load、Button_Encrypt、Button_Decrypt、Axes_Original、Axes_Encrypted、Axes_Decrypted、Edit_BasePos、Edit_BasePix、Edit_StartIdx。這樣回調(diào)函數(shù)里一眼就能分清。早期我用過自動(dòng)生成的名字比如EditField_2、Button_3時(shí)間一長(zhǎng)自己都看不懂項(xiàng)目一復(fù)雜就亂套。3.2 核心回調(diào)函數(shù)怎么組織加密流程加密按鈕的回調(diào)邏輯大概是這樣% 讀取參數(shù) base_pos str2double(app.Edit_BasePos.Value); base_pix str2double(app.Edit_BasePix.Value); start_idx str2double(app.Edit_StartIdx.Value); % 取當(dāng)前顯示的圖像數(shù)據(jù) img app.OriginalImage; % 調(diào)用加密函數(shù) [encrypted_img, idx_map, key_stream] encrypt_halton(img, base_pos, base_pix, start_idx); % 更新顯示 app.EncryptedImage encrypted_img; imshow(encrypted_img, Parent, app.Axes_Encrypted);加密函數(shù)內(nèi)部可以拆成三個(gè)子函數(shù)halton_value負(fù)責(zé)生成序列值permute_position負(fù)責(zé)位置擾亂diffuse_pixel負(fù)責(zé)像素?cái)U(kuò)散。這樣代碼結(jié)構(gòu)清楚后續(xù)加解密復(fù)用時(shí)也不會(huì)重復(fù)寫邏輯。解密按鈕的回調(diào)基本對(duì)稱先讀取相同的參數(shù)調(diào)用decrypt_halton函數(shù)內(nèi)部先逆像素?cái)U(kuò)散再逆位置擾亂最后顯示。這塊最大的坑在于加密時(shí)用到的idx_map和key_stream需要能重新生成。我的做法是不保存中間變量而是在解密函數(shù)里用相同的Halton參數(shù)現(xiàn)場(chǎng)重新生成避免GUI里保存中間狀態(tài)造成混亂。3.3 拿到源碼后先改哪幾個(gè)參數(shù)很多朋友拿到帶GUI的Matlab源碼第一反應(yīng)是直接點(diǎn)運(yùn)行但這樣往往得不到理想結(jié)果。我建議先做三件事第一確認(rèn)當(dāng)前Matlab版本。App Designer創(chuàng)建的.mlapp文件在舊版本里打不開至少要R2016b以上如果版本較老就得改用GUIDE版本或直接調(diào)用.m函數(shù)。第二找到參數(shù)初始化代碼。一般在startupFcn里會(huì)有類似app.Edit_BasePos.Value 2;的賦值先把基數(shù)和起始序號(hào)改成自己想要的然后用同一組參數(shù)加密解密驗(yàn)證通。第三確認(rèn)圖像路徑。GUI代碼里如果寫死了某個(gè)圖片路徑運(yùn)行環(huán)境一變就會(huì)報(bào)錯(cuò)。最好在讀取圖像回調(diào)里自己選圖不要在命令行里臨時(shí)改路徑。3.4 運(yùn)行環(huán)境與常見報(bào)錯(cuò)Matlab里跑這個(gè)項(xiàng)目常見的報(bào)錯(cuò)主要集中在這幾個(gè)地方報(bào)錯(cuò)信息出現(xiàn)原因解決方式Undefined function haltonset用了內(nèi)置haltonset但沒裝統(tǒng)計(jì)工具箱換成自寫halton_value函數(shù)或安裝工具箱Index exceeds array bounds置亂索引方向?qū)懛椿蛐蛄虚L(zhǎng)度不匹配檢查排序索引賦值方向確認(rèn)圖像長(zhǎng)度一致Class mismatch: double vs uint8像素向量類型不一致導(dǎo)致bitxor報(bào)錯(cuò)統(tǒng)一轉(zhuǎn)double或統(tǒng)一轉(zhuǎn)uint8Error using imshowGUI坐標(biāo)軸父對(duì)象傳錯(cuò)確保imshow里寫Parent, app.Axes_XX還有一個(gè)隱藏問題中文路徑。舊版Matlab對(duì)中文路徑支持不好圖片放在純英文路徑下最省事。我最初把圖片放在“D:\測(cè)試圖片\lena.png”結(jié)果在部分機(jī)器上一運(yùn)行就提示讀取失敗改成“D:\test_images\lena.png”后一切正常。4. 相關(guān)性分析怎么評(píng)價(jià)加密效果4.1 相鄰像素相關(guān)性的計(jì)算邏輯圖像加密效果好不好最常見的一個(gè)定量指標(biāo)就是相鄰像素相關(guān)性。自然圖像里一個(gè)像素和它左邊、上邊、斜上方的像素通常非常接近相關(guān)系數(shù)接近1。而好的加密算法應(yīng)當(dāng)像“打碎”這種關(guān)系讓相鄰像素不再有規(guī)律相關(guān)系數(shù)趨向于0。計(jì)算方法是在圖像中隨機(jī)抽取若干對(duì)相鄰像素比如水平方向取每行的第1列和第2列、第2列和第3列……然后代入相關(guān)系數(shù)公式function r pixel_correlation(pairs) x pairs(:, 1); y pairs(:, 2); mx mean(x); my mean(y); cov_xy sum((x - mx) .* (y - my)); dx sqrt(sum((x - mx).^2)); dy sqrt(sum((y - my).^2)); r cov_xy / (dx * dy eps); end采樣數(shù)量不需要跑滿全圖隨機(jī)抽取3000到5000對(duì)就已經(jīng)很穩(wěn)定。關(guān)鍵是采樣方式要區(qū)分方向水平方向是img(:, 1:end-1)和img(:, 2:end)垂直方向是img(1:end-1, :)和img(2:end, :)對(duì)角方向則是img(1:end-1, 1:end-1)和img(2:end, 2:end)。4.2 加密前后的數(shù)據(jù)對(duì)照實(shí)驗(yàn)我拿512×512的灰度Lena圖做了完整測(cè)試每組隨機(jī)抽4000對(duì)像素結(jié)果如下方向明文相關(guān)系數(shù)密文相關(guān)系數(shù)解密后相關(guān)系數(shù)水平0.97430.01280.9741垂直0.97210.01060.9723對(duì)角0.95880.01420.9587密文三個(gè)方向的相關(guān)性都?jí)旱搅?.02以下說明相鄰像素之間的線性關(guān)聯(lián)被徹底破壞。解密圖像的相關(guān)性回到0.97以上也證明加解密過程沒有引入肉眼可見的質(zhì)量損失。這里有一點(diǎn)要注意相關(guān)系數(shù)只衡量線性關(guān)系并不代表絕對(duì)無泄漏。某些非線性關(guān)聯(lián)可能仍然存在所以相關(guān)性分析通常還要配合直方圖、信息熵等指標(biāo)一起看。4.3 相關(guān)性系數(shù)之外還需要看什么如果項(xiàng)目要求寫完整實(shí)驗(yàn)報(bào)告只給相關(guān)系數(shù)還不夠。我會(huì)再補(bǔ)充三個(gè)指標(biāo)直方圖對(duì)比、信息熵和差分攻擊指標(biāo)。直方圖對(duì)比是最直觀的明文圖像直方圖往往高低起伏集中在部分灰度級(jí)加密后直方圖應(yīng)當(dāng)接近均勻分布說明像素值沒有明顯的統(tǒng)計(jì)偏向。信息熵則用公式H -sum(p_i * log2(p_i))計(jì)算8位灰度圖理想值是8實(shí)測(cè)加密圖像的信息熵能到7.997以上就算合格。差分攻擊指標(biāo)是NPCR和UACI分別衡量“改變一個(gè)像素后密文變化的百分比”和“變化幅度的平均值”一般要求NPCR大于99%UACI在33%左右。這些指標(biāo)在Matlab里實(shí)現(xiàn)都不復(fù)雜而且都能在GUI里加一個(gè)“指標(biāo)計(jì)算”按鈕一鍵輸出。如果你只是演示加密過程相關(guān)性分析已經(jīng)足夠如果要寫成畢設(shè)或項(xiàng)目文檔建議把信息熵和直方圖也放進(jìn)去工作量不大但會(huì)讓結(jié)果更完整。5. 實(shí)測(cè)過程中的坑和應(yīng)對(duì)5.1 Halton索引生成時(shí)最容易踩的邊界坑Halton序列從第幾個(gè)數(shù)字開始算決定了整個(gè)置亂表。很多參考代碼習(xí)慣從0開始因?yàn)閿?shù)值上從0開始更符合數(shù)學(xué)定義。但對(duì)Matlab來說數(shù)組索引從1開始如果生成序列時(shí)包含了halton_value(0, base)第一個(gè)值會(huì)是0排序后0會(huì)排最前面這本身沒問題但在生成“從1到L的索引”時(shí)0會(huì)被當(dāng)作下標(biāo)直接報(bào)越界。我的處理方式是halton_value函數(shù)里n從1開始start_idx參數(shù)也默認(rèn)從1開始保證生成的序列長(zhǎng)度與圖像像素?cái)?shù)嚴(yán)格相等。另外浮點(diǎn)精度偶爾會(huì)導(dǎo)致兩個(gè)極其接近的序列值在排序時(shí)順序不穩(wěn)定但實(shí)際測(cè)試中概率很低。如果實(shí)在擔(dān)心可以在生成序列后加一個(gè)微小擾動(dòng)比如seq seq (1:L) * 1e-12保證排序結(jié)果唯一且可復(fù)現(xiàn)。5.2 彩色圖像與灰度圖像的處理差異很多圖像加密教程默認(rèn)使用灰度圖但現(xiàn)實(shí)項(xiàng)目里更多是RGB彩色圖。彩色圖和灰度圖最大的區(qū)別是通道數(shù)量灰度圖是一個(gè)M×N的二維矩陣彩色圖是M×N×3的三維矩陣。處理彩色圖時(shí)我有兩種思路。第一種是把三通道拆開每個(gè)通道獨(dú)立做置亂和擴(kuò)散最后合并第二種是把三通道拉成一個(gè)L×3的矩陣讓位置擾亂對(duì)每一行的三個(gè)通道一起重排像素?cái)_亂則對(duì)每個(gè)通道分別生成密鑰流。我實(shí)際更推薦第二種因?yàn)樗鼙3滞晃恢孟袼氐娜ǖ勒w移動(dòng)解密后色彩還原更穩(wěn)定。實(shí)現(xiàn)時(shí)要注意bitxor函數(shù)的輸入必須是同類型?;叶葓D直接uint8和uint8異或沒問題彩色圖分通道做的時(shí)候千萬別把double類型的數(shù)據(jù)直接傳給bitxor否則會(huì)報(bào)錯(cuò)。5.3 解密結(jié)果異常時(shí)的排查順序我調(diào)試這個(gè)GUI的時(shí)候遇到過好幾次解密出來“花屏”的情況。排查順序基本是固定的我建議照著這個(gè)順序來先看像素?cái)_亂解的是不是逆操作。帶反饋的加密必須倒著解如果用了正序循環(huán)結(jié)果是全亂。再檢查位置擾亂方向加密時(shí)用的是shuffled_vec(idx(i)) img_vec(i)解密時(shí)就必須構(gòu)造reverse_idx(idx) 1:L然后用recovered_vec dec_vec(reverse_idx)。很多朋友解密失敗都是因?yàn)檫@里少了一步。如果以上兩步都沒問題再看參數(shù)是否一致?;鶖?shù)和起始序號(hào)必須和加密時(shí)完全相同尤其是start_idx我調(diào)試時(shí)有一次加密用的start_idx10解密時(shí)嫌數(shù)字大改成了1解密出來的圖像就完全不對(duì)。這個(gè)參數(shù)雖然只是偏移量但它是密鑰的一部分不能隨意改。最后再說一個(gè)經(jīng)驗(yàn)如果解密圖像是“能看出輪廓但顏色不對(duì)”問題基本出在像素?cái)_亂逆運(yùn)算如果解密圖像是“雪花噪聲完全無內(nèi)容”問題多半出在位置擾亂方向。根據(jù)這兩種現(xiàn)象可以快速定位到底哪一步寫錯(cuò)了。這套方法整體做下來性能上也不差。512×512灰度圖完整加密一輪在我的筆記本上大約0.3秒GUI界面完全感覺不到卡頓。如果要做更大尺寸的圖像建議先降采樣或分塊處理否則位置擾亂部分生成的序列變長(zhǎng)排序耗時(shí)也會(huì)跟著上去。算法本身不難難的是把置亂、擴(kuò)散、逆操作和GUI之間的邏輯理順。只要順序?qū)α撕竺娴南嚓P(guān)性分析和指標(biāo)驗(yàn)證都會(huì)非常順。