1、常 见 的 插 值 方 法 及 其 原 理这 一 节 无 可 避 免 要 接 触 一 些 数 学 知 识 , 为 了 让 本 文 通 俗 易 懂 , 我 们 尽 量 绕 开 讨 厌的 公 式 等 。 为 了 进 一 步 的 简 化 难 度 , 我 们 把 讨 论 从 二 维 图 像 降 到 一 维 上 。首 先 来 看 看 最 简 单 的 最 临 近 像 素 插 值 。A,B 是 原 图 上 已 经 有 的 点 , 现 在 我 们 要 知 道 其 中 间 X 位 置 处 的 像 素 值 。 我 们找 出 X 位 置 和 A,B 位 置 之 间 的 距 离 d1,d2, 如 图 , d2 要 小
2、 于 d1,所 以 我 们 就 认 为X 处 像 素 值 的 大 小 就 等 于 B 处 像 素 值 的 大 小 。显 然 , 这 种 方 法 是 非 常 苯 的 , 同 时 会 带 来 明 显 的 失 真 。 在 A,B 中 点 处 的 像 素值 会 突 然 出 现 一 个 跳 跃 , 这 就 是 为 什 么 会 出 现 马 赛 克 和 锯 齿 等 明 显 走 样 的 原 因 。 最临 近 插 值 法 唯 一 的 优 点 就 是 速 度 快 。图 10, 最 临 近 法 插 值 原 理接 下 来 是 稍 微 复 杂 点 的 线 性 插 值 ( Linear)线 性 插 值 也 很 好 理 解
3、 , AB 两 点 的 像 素 值 之 间 , 我 们 认 为 是 直 线 变 化 的 , 要 求X 点 处 的 值 , 只 需 要 找 到 对 应 位 置 直 线 上 的 一 点 即 可 。 换 句 话 说 , A,B 间 任 意 一点 的 值 只 跟 A,B 有 关 。 由 于 插 值 的 结 果 是 连 续 的 , 所 以 视 觉 上 会 比 最 小 临 近 法 要 好一 些 。 线 性 插 值 速 度 稍 微 要 慢 一 点 , 但 是 效 果 要 好 不 少 。 如 果 讲 究 速 度 , 这 是 个 不错 的 折 衷 。图 11, 线 性 插 值 原 理其 他 插 值 方 法立 方
4、 插 值 , 样 条 插 值 等 等 , 他 们 的 目 的 是 试 图 让 插 值 的 曲 线 显 得 更 平 滑 , 为 了 达到 这 个 目 的 , 他 们 不 得 不 利 用 到 周 围 若 干 范 围 内 的 点 , 这 里 的 数 学 原 理 就 不 再 详 述了 。图 12, 高 级 的 插 值 原 理如 图 , 要 求 B,C 之 间 X 的 值 , 需 要 利 用 B,C 周 围 A,B,C,D 四 个 点 的 像 素 值 ,通 过 某 种 计 算 , 得 到 光 滑 的 曲 线 , 从 而 算 出 X 的 值 来 。 计 算 量 显 然 要 比 前 两 种 大许 多 。好
5、了 , 以 上 就 是 基 本 知 识 。 所 谓 两 次 线 性 和 两 次 立 方 实 际 上 就 是 把 刚 才 的 分 析 拓展 到 二 维 空 间 上 , 在 宽 和 高 方 向 上 作 两 次 插 值 的 意 思 。 在 以 上 的 基 础 上 , 有 的 软 件还 发 展 了 更 复 杂 的 改 进 的 插 值 方 式 譬 如 S-SPline, Turbo Photo 等 。 他 们 的 目 的 是使 边 缘 的 表 现 更 完 美 。插 值 (Interpolation), 有 时 也 称 为 “重 置 样 本 ”, 是 在 不 生 成 像 素 的 情 况 下增 加 图 像
6、像 素 大 小 的 一 种 方 法 , 在 周 围 像 素 色 彩 的 基 础 上 用 数 学 公 式 计 算 丢 失 像 素的 色 彩 。 简 单 地 说 , 插 值 是 根 据 中 心 像 素 点 的 颜 色 参 数 模 拟 出 周 边 像 素 值 的 方 法 ,是 数 码 相 机 特 有 的 放 大 数 码 照 片 的 软 件 手 段 。一 、 认 识 插 值 的 算 法“插 值 ”最 初 是 电 脑 术 语 , 后 来 引 用 到 数 码 图 像 上 来 。 图 像 放 大 时 , 像 素 也 相应 地 增 加 , 但 这 些 增 加 的 像 素 从 何 而 来 ? 这 时 插 值 就
7、 派 上 用 场 了 。 插 值 就 是 在 不 生成 像 素 的 情 况 下 增 加 图 像 像 素 大 小 的 一 种 方 法 , 在 周 围 像 素 色 彩 的 基 础 上 用 数 学 公式 计 算 丢 失 像 素 的 色 彩 (也 有 些 相 机 使 用 插 值 , 人 为 地 增 加 图 像 的 分 辨 率 )。 所以 在 放 大 图 像 时 , 图 像 看 上 去 会 比 较 平 滑 、 干 净 。 但 必 须 注 意 的 是 插 值 并 不 能 增 加图 像 信 息 。 以 图 1 为 原 图 (见 图 1), 以 下 是 经 过 不 同 插 值 算 法 处 理 的 图 片 。1
8、.最 近 像 素 插 值 算 法最 近 像 素 插 值 算 法 (Nearest Neighbour Interpolation)是 最 简 单 的 一 种 插值 算 法 , 当 图 片 放 大 时 , 缺 少 的 像 素 通 过 直 接 使 用 与 之 最 接 近 的 原 有 像 素 的 颜 色 生成 , 也 就 是 说 照 搬 旁 边 的 像 素 , 这 样 做 的 结 果 是 产 生 了 明 显 可 见 的 锯 齿 (见 图 2)。2.双 线 性 插 值 算 法双 线 性 插 值 算 法 (Bilinear Interpolation)输 出 的 图 像 的 每 个 像 素 都 是 原
9、图中 四 个 像 素 (22)运 算 的 结 果 , 这 种 算 法 极 大 程 度 上 消 除 了 锯 齿 现 象 (见 图 3)。3.双 三 次 插 值 算 法双 三 次 插 值 算 法 (Bicubic Interpolation)是 上 一 种 算 法 的 改 进 算 法 , 它 输 出图 像 的 每 个 像 素 都 是 原 图 16 个 像 素 (44)运 算 的 结 果 (见 图 4)。 这 种 算 法 是 一种 很 常 见 的 算 法 , 普 遍 用 在 图 像 编 辑 软 件 、 打 印 机 驱 动 和 数 码 相 机 上 。4.分 形 算 法分 形 算 法 (Fractal
10、Interpolation)是 Altamira Group 提 出 的 一 种 算 法 ,这 种 算 法 得 到 的 图 像 跟 其 他 算 法 相 比 更 清 晰 、 更 锐 利 (见 图 5)。现 在 有 许 多 数 码 相 机 厂 商 将 插 值 算 法 用 在 了 数 码 相 机 上 , 并 将 通 过 算 法 得 到 的分 辨 率 值 大 肆 宣 传 , 固 然 他 们 的 算 法 比 双 三 次 插 值 算 法 等 算 法 先 进 很 多 , 但 是 事 实是 图 像 的 细 节 不 是 凭 空 造 出 来 的 。 因 为 插 值 分 辨 率 是 数 码 相 机 通 过 自 身
11、的 内 置 软 件来 增 加 图 像 的 像 素 , 从 而 达 到 增 大 分 辨 率 的 效 果 。二 、 插 值 的 影 响使 用 数 码 变 焦 拍 出 来 的 照 片 不 清 晰 , 这 是 数 码 变 焦 最 遭 人 垢 病 的 地 方 , 事 实 上 ,这 只 是 一 种 片 面 的 说 法 。数 码 变 焦 对 照 片 清 晰 度 的 影 响 有 多 大 , 取 决 于 数 码 相 机 在 变 焦 时 , CCD 是 否进 行 了 插 值 运 算 。 在 使 用 高 像 素 的 情 况 下 , 如 果 采 用 数 码 变 焦 进 行 拍 摄 , 则 此 时 CCD并 不 会 有
12、 任 何 插 值 运 算 , 数 码 变 焦 对 最 终 得 到 的 数 码 照 片 的 清 晰 度 的 影 响 将 会 因 此而 变 得 极 其 有 限 。 举 个 例 子 , 一 台 CCD 像 素 为 520 万 、 最 大 分 辨 率 为25601920 的 数 码 相 机 , 如 果 采 用 2的 数 码 变 焦 来 进 行 拍 摄 的 话 , 那 么 成 像 过程 中 只 会 有 一 半 CCD 在 工 作 。 换 句 话 说 , 数 码 相 机 并 不 会 使 用 类 似 “在 一 个 像素 点 周 围 添 加 八 个 像 素 点 ”的 插 值 算 法 进 行 成 像 , 而 是
13、 通 过 降 低 分 辨 率 的 方 法 , 即1280960 这 个 分 辨 率 指 标 来 进 行 成 像 。 对 于 一 般 的 数 码 照 片 来 说 , 1280960这 个 分 辨 率 指 标 已 经 足 够 优 秀 了 , 它 与 25601920 分 辨 率 的 差 别 将 会 因 为 没 有插 值 运 算 的 参 与 而 变 得 可 以 接 受 。 不 过 这 种 现 象 只 限 于 某 些 比 较 高 级 的 数 码 相 机 ,对 于 那 些 千 元 以 下 的 定 焦 数 码 相 机 来 说 , 使 用 数 码 变 焦 就 意 味 着 必 然 的 插 值 运 算 ,牺 牲
14、 分 辨 率 的 后 果 使 得 照 片 拍 摄 者 只 能 有 两 个 选 择 :要 么 得 到 一 张 模 糊 不 清 的“全 尺 寸 ”照 片 、 要 么 得 到 一 张 质 量 可 以 保 证 但 分 辨 率 只 有 类 似 320240 这 样的 “迷 你 ”照 片 。图像插值放大的方法有很多,最主要的有二次线性插值和三次线性插值这两种。这次我把自己的程序中所用的二次线性插值的算法公布给大家,希望对各位要使用 VB 写类似程序的朋友有所帮助。程序中用到的 API、数据类型、全局变量的定义请参考上一篇: VB 实现图像在数据库的存储与显示 Public Sub ZoomImage(By
15、Val OutPutWidth As Long, ByVal OutputHeight As Long)Dim I As LongDim L As LongDim X As LongDim Y As LongDim Xb As LongDim Yb As LongDim Xe As LongDim Ye As LongDim M As IntegerDim N As IntegerDim CurR As LongDim CurG As LongDim CurB As LongDim NxtR As IntegerDim NxtG As IntegerDim NxtB As IntegerDim
16、 DR As SingleDim DG As SingleDim DB As SingleDim DRt As SingleDim DGt As SingleDim DBt As SingleDim Xratio As SingleDim Yratio As SingleDim CurStep As SingleDim NxtStep As SingleDim NegN As SingleOn Error GoTo ErrLineIf Not CanZoom Then Exit SubDone = FalseOutPutWid = OutPutWidth - 1OutPutHei = Outp
17、utHeight - 1I = (Bits 8) - 1ReDim ColTmp(I, InPutWid, OutPutHei) 先从 Y 方向进行缩放处理,结果保存在此中间数组内ReDim ColOut(I, OutPutWid, OutPutHei)Xratio = OutPutWid / InPutWidYratio = OutPutHei / InPutHeiTimeZoom = timeGetTimeNegN = 1 / Int(Yratio + 1)For X = 0 To InPutWidCurR = ColVal(0, X, 0)CurG = ColVal(1, X, 0)Cu
18、rB = ColVal(2, X, 0)CurStep = 0NxtStep = 0For Y = 0 To InPutHei - 1NxtStep = CurStep + YratioYb = CurStepYe = NxtStepN = Ye - YbColTmp(0, X, Yb) = CurRColTmp(1, X, Yb) = CurGColTmp(2, X, Yb) = CurBM = Y + 1NxtR = ColVal(0, X, M)NxtG = ColVal(1, X, M)NxtB = ColVal(2, X, M)If N 1 ThenDRt = (NxtR - Cur
19、R) * NegNDGt = (NxtG - CurG) * NegNDBt = (NxtB - CurB) * NegNDR = 0DG = 0DB = 0For L = Yb + 1 To Ye - 1DR = DR + DRtDG = DG + DGtDB = DB + DBtColTmp(0, X, L) = CurR + DR ColTmp(1, X, L) = CurG + DG ColTmp(2, X, L) = CurB + DB NextEnd IfCurStep = NxtStepCurR = NxtRCurG = NxtGCurB = NxtBNextColTmp(0,
20、X, OutPutHei) = NxtRColTmp(1, X, OutPutHei) = NxtGColTmp(2, X, OutPutHei) = NxtBNextNegN = 1 / Int(Xratio + 1)For Y = 0 To OutPutHeiCurR = ColTmp(0, 0, Y)CurG = ColTmp(1, 0, Y)CurB = ColTmp(2, 0, Y)CurStep = 0NxtStep = 0For X = 0 To InPutWid - 1NxtStep = CurStep + XratioXb = CurStepXe = NxtStepN = X
21、e - XbColOut(0, Xb, Y) = CurRColOut(1, Xb, Y) = CurGColOut(2, Xb, Y) = CurBM = X + 1NxtR = ColTmp(0, M, Y)NxtG = ColTmp(1, M, Y)NxtB = ColTmp(2, M, Y)If N 1 ThenDRt = (NxtR - CurR) * NegNDGt = (NxtG - CurG) * NegNDBt = (NxtB - CurB) * NegNDR = 0DG = 0DB = 0For L = Xb + 1 To Xe - 1DR = DR + DRtDG = D
22、G + DGtDB = DB + DBtColOut(0, L, Y) = CurR + DRColOut(1, L, Y) = CurG + DG ColOut(2, L, Y) = CurB + DB NextEnd IfCurStep = NxtStepCurR = NxtRCurG = NxtGCurB = NxtBNextColOut(0, OutPutWid, Y) = NxtRColOut(1, OutPutWid, Y) = NxtGColOut(2, OutPutWid, Y) = NxtBNextDone = TrueTimeZoom = timeGetTime - Tim
23、eZoomCanPut = TrueExit SubErrLine:MsgBox Err.DescriptionEnd Sub全局变量定义:Dim ColTmp() As Byte 用于保存插值中间变量Dim OutPutHei As Long 要插值的目标高度Dim OutPutWid As Long 要插值的目标宽度Public TimeZoom As Long 插值运算使用的时间简单解释一下关于二次线性插值算法。(为了说明算法本身,我们只计算这个图片的红色分量,因为红绿蓝三种颜色的计算方法完全相同)假设我们有一个很简单的图片,图片只有 4 个像素(2*2 )A BC D现在我们要把这个图
24、片插值到 9 个像素:3*3A ab Bac abcd bdC cd D其中大写的字母代表原来的像素,小写字母代表插值得到的新像素。想必看到这个图,大家心里已经有了这个算法了。ab=(A+B) / 2 cd=(C+D) / 2ac=(A+C) / 2bd=(B+D) / 2abcd=(ab+cd) / 2(A+B+C+D) / 4推导:ab= A + (B-A) / 2cd=C +(D-C) / 2.很简单,对吧,先从一个方向把只涉及两个原始像素的新像素算出来。我们这里假定先计算水平方向。而在算垂直方向的插值的时候,因为 ab 和 cd 已经在前面算好了,所以abcd 的计算也和计算 ac 和 bd 没有任何区别了。有可能为有朋友已经想到把原来的图像插值到 4*4 或 5*5 的方法了。