Skip to content

Commit

Permalink
修复中值滤波不能消除椒盐噪声的问题、滤波时没用到原数据的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
xfgryujk committed Jul 21, 2018
1 parent e226234 commit 69816d7
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 56 deletions.
8 changes: 4 additions & 4 deletions src/codec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let ctx = canvas.getContext('2d')

// 加密图片,返回data URL
export function encrypt (img) {
return doCodecCommon(img, imgData =>
return doCodecCommon(img, imgData =>
Codec.createCodec(getConfig().codecName, imgData).encrypt()
)
}
Expand All @@ -33,7 +33,7 @@ export async function decrypt (originImg) {

originImg.src = doCodecCommon(img, imgData => {
imgData = Codec.createCodec(getConfig().codecName, imgData).decrypt()
postProcess(imgData);
postProcess(imgData)
return imgData
})
}
Expand All @@ -43,7 +43,7 @@ function doCodecCommon (img, handleImgData) {
[canvas.width, canvas.height] = [img.width, img.height]
// 微博会把透明图片和白色混合
ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, img.width, img.height)
ctx.fillRect(0, 0, img.width, img.height)
ctx.drawImage(img, 0, 0)
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height)
imgData = handleImgData(imgData);
Expand Down Expand Up @@ -159,7 +159,7 @@ class MoveRgbCodec extends Codec {
}
Codec._codecClasses.MoveRgbCodec = MoveRgbCodec

// 将8x8 像素块随机移动
// 将8x8像素块随机移动
// 由于JPEG是分成8x8的小块在块内压缩,分成8x8小块处理可以避免压缩再解密造成的高频噪声
class Move8x8BlockCodec extends Codec {
encrypt () {
Expand Down
114 changes: 62 additions & 52 deletions src/imgproc.js
Original file line number Diff line number Diff line change
@@ -1,97 +1,107 @@
// 将图像数据分离为各通道一个数组,返回包含各通道的数组
export function splitChannels (data, nChannels = 4) {
let nPixels = data.length / nChannels
let channels = []
for (let i = 0; i < nChannels; i++) {
channels.push(new Uint8ClampedArray(nPixels))
}
for (let iChannel = 0; iChannel < nChannels; iChannel++) {
for (let iPixel = 0; iPixel < nPixels; iPixel++) {
channels[iChannel][iPixel] = data[iPixel * 4 + iChannel]
}
}
return channels
}
// // 将图像数据分离为各通道一个数组,返回包含各通道的数组
// export function splitChannels (data, nChannels = 4) {
// let nPixels = data.length / nChannels
// let channels = []
// for (let i = 0; i < nChannels; i++) {
// channels.push(new Uint8ClampedArray(nPixels))
// }
// for (let iChannel = 0; iChannel < nChannels; iChannel++) {
// for (let iPixel = 0; iPixel < nPixels; iPixel++) {
// channels[iChannel][iPixel] = data[iPixel * 4 + iChannel]
// }
// }
// return channels
// }

// 将多个通道合并为一个数组
export function mergeChannels (channels) {
let nChannels = channels.length
let nPixels = channels[0].length
let data = new Uint8ClampedArray(nChannels * nPixels)
for (let iPixel = 0; iPixel < nPixels; iPixel++) {
for (let iChannel = 0; iChannel < nChannels; iChannel++) {
data[iPixel * 4 + iChannel] = channels[iChannel][iPixel]
}
}
return data
}
// // 将多个通道合并为一个数组
// export function mergeChannels (channels) {
// let nChannels = channels.length
// let nPixels = channels[0].length
// let data = new Uint8ClampedArray(nChannels * nPixels)
// for (let iPixel = 0; iPixel < nPixels; iPixel++) {
// for (let iChannel = 0; iChannel < nChannels; iChannel++) {
// data[iPixel * 4 + iChannel] = channels[iChannel][iPixel]
// }
// }
// return data
// }

// 3x3高斯模糊
export function gaussianBlur (imgData) {
const KERNEL_TOTAL = 16
// JS中只有浮点数,全换成整数应该不能加速?
const KERNEL = [
[1, 2, 1],
[2, 4, 2],
[1, 2, 1]
1 / KERNEL_TOTAL, 2 / KERNEL_TOTAL, 1 / KERNEL_TOTAL,
2 / KERNEL_TOTAL, 4 / KERNEL_TOTAL, 2 / KERNEL_TOTAL,
1 / KERNEL_TOTAL, 2 / KERNEL_TOTAL, 1 / KERNEL_TOTAL
]
const KERNEL_TOTAL = 16

let channels = splitChannels(imgData.data)
let data = imgData.data
let buffer = new Uint8ClampedArray(data.length / 4 * 3)
for (let iChannel = 0; iChannel < 3; iChannel++) {
// 懒得做填充了,边界像素不处理
for (let y = 1; y < imgData.height - 1; y++) {
for (let x = 1; x < imgData.width - 1; x++) {
let sum = 0
for (let kernelY = 0; kernelY < 3; kernelY++) {
for (let kernelX = 0; kernelX < 3; kernelX++) {
sum += channels[iChannel][(y - 1 + kernelY) * imgData.width + (x - 1 + kernelX)] *
KERNEL[kernelY][kernelX]
sum += data[((y - 1 + kernelY) * imgData.width + (x - 1 + kernelX)) * 4 + iChannel] *
KERNEL[kernelY * 3 + kernelX]
}
}
channels[iChannel][y * imgData.width + x] = sum / KERNEL_TOTAL
buffer[(y * imgData.width + x) * 3 + iChannel] = Math.round(sum)
}
}
}

let data = mergeChannels(channels)
for (let i = 0; i < data.length; i++) {
imgData.data[i] = data[i]
}
copy24BitsTo32Bits(data, buffer, imgData.width, imgData.height)
}

// 3x3中值滤波
export function medianBlur (imgData) {
let channels = splitChannels(imgData.data)
let buffer = new Array(3 * 3)
let data = imgData.data
let buffer = new Uint8ClampedArray(data.length / 4 * 3)
let buffer33 = new Uint8ClampedArray(3 * 3)
for (let iChannel = 0; iChannel < 3; iChannel++) {
// 懒得做填充了,边界像素不处理
for (let y = 1; y < imgData.height - 1; y++) {
for (let x = 1; x < imgData.width - 1; x++) {
// 复制图像3x3区域到buffer
// 复制图像3x3区域到buffer33
for (let bufferY = 0; bufferY < 3; bufferY++) {
for (let bufferX = 0; bufferX < 3; bufferX++) {
buffer[bufferY * 3 + bufferX] = channels[iChannel][(y - 1 + bufferY) * imgData.width + (x - 1 + bufferX)]
buffer33[bufferY * 3 + bufferX] = data[((y - 1 + bufferY) * imgData.width + (x - 1 + bufferX)) * 4 + iChannel]
}
}
// 做5次选择排序,第5个成员就是中值
for (let i = 0; i < 5; i++) {
let min = buffer[i]
let min = buffer33[i]
let iMin = i
for (let j = i + 1; j < buffer.length; j++) {
if (buffer[j] < min) {
min = buffer[j]
for (let j = i + 1; j < buffer33.length; j++) {
if (buffer33[j] < min) {
min = buffer33[j]
iMin = j
}
buffer[iMin] = buffer[i]
buffer[i] = min
}
buffer33[iMin] = buffer33[i]
buffer33[i] = min
}
channels[iChannel][y * imgData.width + x] = buffer[4]
buffer[(y * imgData.width + x) * 3 + iChannel] = buffer33[4]
}
}
}

let data = mergeChannels(channels)
for (let i = 0; i < data.length; i++) {
imgData.data[i] = data[i]
copy24BitsTo32Bits(data, buffer, imgData.width, imgData.height)
}

// 将3通道图片复制到4通道图片,忽略边界1像素
function copy24BitsTo32Bits (dstData, srcData, width, height) {
for (let y = 1; y < height - 1; y++) {
let iDst = (y * width + 1) * 4
let iSrc = (y * width + 1) * 3
for (let x = 0; x < width - 1; x++, iDst += 4, iSrc += 3) {
dstData[iDst] = srcData[iSrc]
dstData[iDst + 1] = srcData[iSrc + 1]
dstData[iDst + 2] = srcData[iSrc + 2]
}
}
}

0 comments on commit 69816d7

Please sign in to comment.