Criminisi图像修复MATLAB实现 Criminisi图像修复MATLAB实现这是目前**纹理/结构型破损划痕、物体移除、大面积缺损**的经典算法比传统的TV/Inpainting模型更擅长保持纹理连续性也是Adobe Photoshop“内容识别填充”的早期核心算法之一。一、Criminisi算法核心逻辑Criminisi是基于纹理合成的优先级修复算法核心解决“先修哪里、用什么修”两个问题优先级计算优先修复结构明显梯度强且周围已知信息可靠的区域符合人类视觉“先看轮廓、再看纹理”的习惯。块匹配从完好区域找和待修复块最相似的纹理块复制到破损区域保证纹理一致性。核心公式1. 优先级P(p)C(p)⋅D(p)P(p) C(p) \cdot D(p)P(p)C(p)⋅D(p)C(p)C(p)C(p)置信项衡量待修复块周围已知像素的可靠性初始已知区域C1C1C1破损区域C0C0C0。D(p)D(p)D(p)数据项衡量待修复点所在边界的结构强度梯度在边界法向上的投影值越大结构越明显。2. 置信项更新每次修复完一个块Ψp^\Psi_{\hat{p}}Ψp^​​块内新修复像素的置信度统一设为当前块的置信度C(p^)C(\hat{p})C(p^​)。二、MATLAB实现1. 主函数criminisi_inpaint.mfunction[inpainted_img,mask]criminisi_inpaint(img,mask,patch_size)% CRIMINISI_INPAINT 基于Criminisi算法的图像修复% img: 输入图像 (灰度图uint8/ double)% mask: 破损掩码 (0破损区域255完好区域和img同尺寸)% patch_size: 修复块大小 (奇数推荐9/11/15)% inpainted_img: 修复后图像% mask: 更新后的掩码%% 参数初始化 ifnargin3,patch_size9;endhalf_patchfloor(patch_size/2);max_iter1000;% 最大迭代次数防止死循环alpha1e-6;% 归一化常数避免除零% 转double便于计算ifisa(img,uint8),imgim2double(img);endifisa(mask,uint8),maskim2double(mask);endmaskim2bw(mask,0.5);% 确保mask是二值0/1[rows,cols]size(img);% 置信度矩阵完好区域1破损区域0Cdouble(mask);% 破损区域标记Φ破损Ω完好Phi~mask;% 逻辑矩阵破损为trueOmegamask;% 逻辑矩阵完好的为true%% 预计算图像梯度 % 用Sobel算子计算梯度x/y方向[gx,gy]imgradientxy(img,sobel);[~,grad_mag]imgradient(gx,gy);% 梯度幅值grad_mag_maxmax(grad_mag(:));% 梯度幅值最大值用于归一化%% 主修复循环 fprintf(开始Criminisi修复...\n);iter0;whileany(Phi(:))itermax_iter iteriter1;% ---------- 1. 找破损区域的边界δΦ ----------% 形态学操作腐蚀完好区域得到边界eroded_Omegaimerode(Omega,strel(disk,1));boundaryOmega~eroded_Omega;% 边界点完好区域的外围[b_y,b_x]find(boundary);% 边界点的坐标ifisempty(b_y),break;end% 无边界修复完成% ---------- 2. 计算每个边界点的优先级 ----------Pzeros(length(b_y),1);% 优先级数组fori1:length(b_y)p_yb_y(i);p_xb_x(i);% ---- 2.1 计算置信项C(p) ----% 取以p为中心的块裁剪边界y_minmax(1,p_y-half_patch);y_maxmin(rows,p_yhalf_patch);x_minmax(1,p_x-half_patch);x_maxmin(cols,p_xhalf_patch);% 块内的已知像素的置信度平均值block_CC(y_min:y_max,x_min:x_max);block_OmegaOmega(y_min:y_max,x_min:x_max);ifsum(block_Omega(:))0C_p0;elseC_pmean(block_C(block_Omega));end% ---- 2.2 计算数据项D(p) ----% 边界法向量n指向破损区域内部掩码梯度的反方向% 用中心差分计算掩码梯度ifp_x1,nxmask(p_y,p_x1)-mask(p_y,p_x);elseifp_xcols,nxmask(p_y,p_x)-mask(p_y,p_x-1);elsenxmask(p_y,p_x1)-mask(p_y,p_x-1);endifp_y1,nymask(p_y1,p_x)-mask(p_y,p_x);elseifp_yrows,nymask(p_y,p_x)-mask(p_y-1,p_x);elsenymask(p_y1,p_x)-mask(p_y-1,p_x);endn_normsqrt(nx^2ny^2eps);nx-nx/n_norm;% 取反指向破损内部ny-ny/n_norm;% 图像梯度在法向量上的投影grad_dot_nabs(gx(p_y,p_x)*nxgy(p_y,p_x)*ny);D_pgrad_dot_n/(alphagrad_mag_max);% 归一化% ---- 2.3 总优先级 ----P(i)C_p*D_p;end% ---------- 3. 选优先级最高的点 ----------[~,idx]max(P);p_hat_yb_y(idx);p_hat_xb_x(idx);% ---------- 4. 取以待修复点为中心的块Ψ_p̂ ----------y_minmax(1,p_hat_y-half_patch);y_maxmin(rows,p_hat_yhalf_patch);x_minmax(1,p_hat_x-half_patch);x_maxmin(cols,p_hat_xhalf_patch);patch_phiPhi(y_min:y_max,x_min:x_max);% 块内的破损区域patch_omegaOmega(y_min:y_max,x_min:x_max);% 块内的完好区域% ---------- 5. 在完好区域搜索最佳匹配块 ----------min_ssdinf;best_q_yp_hat_y;best_q_xp_hat_x;% 遍历所有完好区域的可能块中心[omega_y,omega_x]find(Omega);fori1:length(omega_y)q_yomega_y(i);q_xomega_x(i);% 块不能超出图像边界q_yminmax(1,q_y-half_patch);q_ymaxmin(rows,q_yhalf_patch);q_xminmax(1,q_x-half_patch);q_xmaxmin(cols,q_xhalf_patch);% 块尺寸必须和待修复块一致if(q_ymax-q_ymin)~(y_max-y_min)||...(q_xmax-q_xmin)~(x_max-x_min)continue;end% 计算SSD平方差和src_blockimg(q_ymin:q_ymax,q_xmin:q_xmax);dst_blockimg(y_min:y_max,x_min:x_max);ssdsum((src_block(patch_omega)-dst_block(patch_omega)).^2,all);ifssdmin_ssd min_ssdssd;best_q_yq_y;best_q_xq_x;best_q_yminq_ymin;best_q_ymaxq_ymax;best_q_xminq_xmin;best_q_xmaxq_xmax;endend% ---------- 6. 复制匹配块到破损区域 ----------src_blockimg(best_q_ymin:best_q_ymax,best_q_xmin:best_q_xmax);% 只复制破损的部分img(y_min:y_max,x_min:x_max)src_block.*double(patch_phi)...img(y_min:y_max,x_min:x_max).*double(patch_omega);% ---------- 7. 更新置信度和掩码 ----------C(y_min:y_max,x_min:x_max)C(y_min:y_max,x_min:x_max).*double(patch_omega)...P(idx).*double(patch_phi);Phi(y_min:y_max,x_min:x_max)false;% 修复的区域不再是破损Omega(y_min:y_max,x_min:x_max)true;% 进度提示ifmod(iter,10)0fprintf(迭代 %d 次剩余破损像素: %d\n,iter,sum(Phi(:)));endendfprintf(修复完成总迭代次数: %d\n,iter);inpainted_imgimg;maskOmega;end2. 测试脚本demo_criminisi.m%% demo_criminisi.m Criminisi算法示例clear;clc;close all;%% 1. 准备输入图像和破损掩码 % 读入测试图像Lena图确保路径正确imgimread(lena.png);ifsize(img,3)3img_grayrgb2gray(img);% 转为灰度图彩色图见下文说明elseimg_grayimg;end% 生成破损掩码在图像中心创建一个50x50的矩形破损maskones(size(img_gray));rect_center[size(img_gray,2)/2,size(img_gray,1)/2];% [x, y]rect_size[50,50];% [宽, 高]x1rect_center(1)-rect_size(1)/2;x2rect_center(1)rect_size(1)/2;y1rect_center(2)-rect_size(2)/2;y2rect_center(2)rect_size(2)/2;mask(y1:y2,x1:x2)0;% 破损区域设为0% 可视化破损图像broken_imgimg_gray;broken_img(~mask)0;% 破损区域显示为黑色%% 2. 运行Criminisi修复 patch_size9;% 修复块大小奇数推荐9/11/15[inpainted_img,~]criminisi_inpaint(img_gray,mask,patch_size);%% 3. 结果可视化 figure(Color,white,Position,[1001001200400])subplot(1,3,1)imshow(img_gray)title(原始图像)subplot(1,3,2)imshow(broken_img)title(破损图像中心矩形区域)subplot(1,3,3)imshow(inpainted_img)title(sprintf(Criminisi修复结果块大小%d,patch_size))%% 4. 可选计算修复质量指标 % 如果有原始完整图像可以计算PSNRpsnr_valpsnr(inpainted_img,img_gray);fprintf(修复图像PSNR: %.2f dB\n,psnr_val);参考代码 图像修复算法www.youwenfan.com/contentcsw/82890.html三、关键参数说明参数作用推荐值patch_size修复块大小9/11/15纹理越丰富块越大结构越简单块越小max_iter最大迭代次数1000破损区域大时适当增大掩码制作定义破损区域用画图工具手动标注或代码生成矩形/圆形/自定义形状四、彩色图像修复方法上面的代码是灰度图版本彩色图像修复有两种常用方案方案1逐通道修复简单但可能颜色失真img_colorimread(lena.png);maskimread(mask.png);inpainted_colorzeros(size(img_color));forc1:3[inpainted_color(:,:,c),~]criminisi_inpaint(img_color(:,:,c),mask,9);end方案2HSV空间修复推荐颜色更自然img_hsvrgb2hsv(img_color);% 只在V明度通道修复H色调和S饱和度保持不变[V_inpainted,~]criminisi_inpaint(img_hsv(:,:,3),mask,9);img_hsv(:,:,3)V_inpainted;inpainted_colorhsv2rgb(img_hsv);五、算法优缺点优点擅长修复大面积纹理/结构破损如移除照片中的路人、修复划痕能保持结构的连续性修复结果更符合人类视觉习惯无需训练数据通用性强缺点计算量大全图搜索匹配块512x512图像约需1-5分钟平滑区域容易出现块效应对复杂语义如人脸五官修复效果差六、与其他修复算法的对比算法适用场景优缺点Criminisi大面积纹理/结构破损结构保持好速度慢TV-Inpainting小面积平滑区域破损速度快纹理模糊PatchMatch纹理合成速度快结构保持弱深度学习LaMa/Stable Diffusion复杂语义破损效果好需要训练数据如果你的破损区域是不规则形状如划痕、文字遮挡可以告诉我我帮你修改掩码生成代码如果是彩色图像/实时性要求高也可以给你对应的优化版本。