Created
June 25, 2024 00:29
-
-
Save YuJianrong/a55d1cae0300bb34a59aa161a0f5ea7b to your computer and use it in GitHub Desktop.
2048
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Image Test</title> | |
<style> | |
html, | |
body { | |
overflow-x: auto; | |
overflow-y: scroll; | |
height: 100%; | |
} | |
body, | |
dl, | |
dt, | |
dd, | |
ul, | |
ol, | |
li, | |
pre, | |
form, | |
fieldset, | |
input, | |
p, | |
blockquote, | |
th, | |
td { | |
font-weight: 400; | |
margin: 0; | |
padding: 0; | |
} | |
.left { | |
float: left; | |
left: 0px; | |
margin: 2px; | |
} | |
.leftCanvas { | |
background-color: aquamarine; | |
overflow: auto; | |
width: 500px; | |
display: none; | |
height: calc(100% - 30px); | |
} | |
input.number { | |
display: inline-block; | |
width: 72px; | |
height: 20px; | |
text-align: center; | |
line-height: 20px; | |
cursor: pointer; | |
} | |
</style> | |
<script type="text/javascript" src="opencv.js"></script> | |
</head> | |
<body> | |
<div> | |
<input id="imageSelect" type="file" accept="image/*" /> | |
块宽:<input id="pieceWidth" class="number" type="number" min="0" max="999" value="0"/> | |
块高:<input id="pieceHeight" class="number" type="number" min="0" max="999" value="0"/> | |
<input id="imageProcess" type="button" value="执行" /> | |
<input id="imageSave" type="button" value="保存图片" /> | |
</div> | |
<div class="left leftCanvas"> | |
<canvas id="imgCanvas" width="0" height="0"></canvas> | |
</div> | |
<div class="left"> | |
<canvas id="imgResult" width="0" height="0"></canvas> | |
</div> | |
<div class="left"> | |
<canvas id="imgSave" width="0" height="0"></canvas> | |
</div> | |
<script> | |
var pieceWidth = 0; | |
var pieceHeight = 0; | |
var canvasTemp = document.createElement('canvas'); | |
var ctxTemp = canvasTemp.getContext('2d'); | |
// 读取本地文件 | |
var inputOne = document.getElementById('imageSelect'); | |
inputOne.onchange = function () { | |
// 获取选中的文件列表 | |
var fileList = inputOne.files; | |
var file = fileList[0]; | |
// 读取文件内容 | |
var reader = new FileReader(); | |
reader.readAsDataURL(file); | |
reader.onload = function (e) { | |
// 将结果显示到canvas | |
showCanvas(reader.result); | |
} | |
} | |
// 块大小自动绑定 | |
var inputWidth = document.getElementById('pieceWidth'); | |
inputWidth.onchange=function(){ | |
pieceWidth = inputWidth.value; | |
} | |
var inputHeight = document.getElementById('pieceHeight'); | |
inputHeight.onchange=function(){ | |
pieceHeight = inputHeight.value; | |
} | |
// 指定图片内容显示 | |
function showCanvas1(dataUrl) { | |
var canvas = document.getElementById('imgCanvas'); | |
var ctx = canvas.getContext('2d'); | |
// 加载图片 | |
var img = new Image(); | |
img.onload = function () { | |
canvas.width = img.width; | |
canvas.height = img.height; | |
setTimeout(() => { | |
let src = cv.imread(img); | |
var rgbaPlanes = new cv.MatVector(); | |
cv.split(src, rgbaPlanes); | |
let red = rgbaPlanes.get(0); | |
let green = rgbaPlanes.get(1); | |
let blue = rgbaPlanes.get(2); | |
var t1 = new cv.Mat(); | |
var t2 = new cv.Mat(); | |
var t3 = new cv.Mat(); | |
cv.add(red, green, t1); | |
cv.add(red, blue, t2); | |
cv.add(green, blue, t3); | |
var split_channel_images = [ | |
red, | |
green, | |
blue, | |
t1, | |
t2, | |
t3 | |
]; | |
var size_candidates = []; | |
for (i in split_channel_images) { | |
var image = split_channel_images[i]; | |
var thresh = new cv.Mat(); | |
cv.threshold(image, thresh, 200, 255, cv.THRESH_BINARY); | |
var opened = new cv.Mat(); | |
var element = cv.getStructuringElement(cv.MORPH_OPEN, new cv.Size(5, 5)); | |
cv.morphologyEx(thresh, opened, cv.MORPH_OPEN, element) | |
var binary_image = new cv.Mat(); | |
cv.bitwise_not(opened, binary_image); | |
var contours = new cv.MatVector(); | |
var hierarchy = new cv.Mat(); | |
cv.findContours(binary_image, | |
contours, | |
hierarchy, | |
cv.RETR_LIST, | |
cv.CHAIN_APPROX_SIMPLE); | |
cv.imshow('imgCanvas', thresh); | |
setTimeout(() => { | |
showCanvas3(); | |
}, 100); | |
return; | |
for (var contourIndex = 0; contourIndex < contours.size(); contourIndex++) { | |
var contour = contours.get(contourIndex); | |
var bounding_rect = cv.boundingRect(contour); | |
var contour_area = cv.contourArea(contour); | |
var width = bounding_rect.width; | |
var height = bounding_rect.height; | |
var extent = contour_area / (width * height); | |
var lower_limit = 1 | |
var upper_limit = 200 * 200 | |
var is_square = Math.abs(width - height) < 300; | |
var is_extent_valid = extent >= 0.75; | |
if (is_square && is_extent_valid) { | |
var candidate = (bounding_rect.width + bounding_rect.height) / 2; | |
size_candidates.push(candidate); | |
} | |
} | |
} | |
console.info(size_candidates); | |
cv.imshow('imgCanvas', src); | |
}, 0); | |
} | |
img.src = dataUrl; | |
} | |
function showCanvas3() { | |
var canvas = document.getElementById('imgCanvas'); | |
var ctx = canvas.getContext('2d'); | |
console.info(ctx); | |
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
console.info("*** 开始识别高度 ***"); | |
imgData = imgFindY(imgData, canvas.width, canvas.height); | |
console.info("*** 完成识别高度 ***"); | |
ctx.putImageData(imgData, 0, 0) | |
} | |
function showCanvas(dataUrl) { | |
var canvas = document.getElementById('imgCanvas'); | |
var ctx = canvas.getContext('2d'); | |
// 加载图片 | |
var img = new Image(); | |
img.onload = function () { | |
canvas.width = img.width; | |
canvas.height = img.height; | |
canvasTemp.width = img.width; | |
canvasTemp.height = img.height; | |
// 改变canvas大小后延迟绘图,避免空白 | |
setTimeout(() => { | |
ctx.drawImage(img, 0, 0, img.width, img.height); | |
ctxTemp.drawImage(img, 0, 0, img.width, img.height); | |
var imgData = ctx.getImageData(0, 0, img.width, img.height); | |
var imgDataCopy = new ImageData(img.width, img.height); | |
imgDataCopy.data.set(imgData.data); | |
console.info("*** 灰度化 ***"); | |
imgData = imgToGray(imgDataCopy); | |
// console.info("*** 开始二值化 ***"); | |
// imgData = imgTo2Value(imgData) | |
// console.info("*** 开始腐蚀 ***"); | |
// imgData = erode(imgData, img.width, img.height); | |
// console.info("*** 开始膨胀 ***"); | |
// imgData = dilate(imgData, img.width, img.height); | |
console.info("*** 识别高度 ***"); | |
var maxHeight = imgFindY(imgDataCopy, img.width, img.height); | |
console.info("*** 识别宽度 ***"); | |
var maxWidth = imgFindX(imgDataCopy, img.width, img.height); | |
// var maxWidth = 0; | |
// var imgDataCopy = imgFindX(imgDataCopy, img.width, img.height); | |
// ctx.putImageData(imgDataCopy, 0, 0) | |
console.info("maxWidth=" + maxWidth); | |
console.info("maxHeight=" + maxHeight); | |
if (maxHeight <= 1 || maxWidth <= 1) { | |
return; | |
} | |
pieceWidth = 96;//maxWidth | |
pieceHeight = 128;//maxHeight | |
inputWidth.value = pieceWidth; | |
inputHeight.value = pieceHeight; | |
// 增加画板宽度和高度 | |
canvas.width = img.width + 5 * Math.ceil(img.width / maxWidth) - 5; | |
canvas.height = img.height + 5 * Math.ceil(img.height / maxHeight) - 5; | |
setTimeout(() => { | |
for (var y = 0; y < Math.ceil(img.height / maxHeight); y++) { | |
for (var x = 0; x < Math.ceil(img.width / maxWidth); x++) { | |
var startX = x * maxWidth; | |
var startY = y * maxHeight; | |
var canvasX = x * (maxWidth + 5); | |
var canvasY = y * (maxHeight + 5); | |
var width = maxWidth; | |
var height = maxHeight; | |
if (x == Math.ceil(img.width / maxWidth) - 1 && img.width % maxWidth != 0) { | |
width = img.width % maxWidth; | |
} | |
if (y == Math.ceil(img.height / maxHeight) - 1 && img.height % maxWidth != 0) { | |
height = img.height % maxHeight; | |
} | |
ctx.drawImage(img, startX, startY, width, height, canvasX, canvasY, width, height); | |
} | |
} | |
if (canvas.width > 500) { | |
reSetCanvasSize(); | |
} | |
}, 0); | |
// ctx.putImageData(imgDataCopy, 0, 0) | |
}, 0); | |
} | |
img.src = dataUrl; | |
} | |
// 灰度化 | |
function imgToGray(imgData) { | |
for (var i = 0; i < imgData.data.length; i += 4) { | |
var R = imgData.data[i]; //R(0-255) | |
var G = imgData.data[i + 1]; //G(0-255) | |
var B = imgData.data[i + 2]; //G(0-255) | |
var Alpha = imgData.data[i + 3]; //Alpha(0-255) | |
//var gray = R*0.299 + G*0.587 + B*0.114; | |
var gray = (R + G + B) / 3; | |
imgData.data[i] = gray; | |
imgData.data[i + 1] = gray; | |
imgData.data[i + 2] = gray; | |
imgData.data[i + 3] = Alpha; | |
} | |
return imgData; | |
} | |
// 二值化 | |
function imgTo2Value(imgData) { | |
// 平均值 | |
var s = 0; | |
var c = 0; | |
for (var i = 0; i < imgData.data.length; i += 4) { | |
s += imgData.data[i]; | |
c++; | |
} | |
var a = s / c; | |
for (var i = 0; i < imgData.data.length; i += 4) { | |
var R = imgData.data[i]; | |
var gray = 0; | |
if (R > a) { | |
gray = 255; | |
} | |
imgData.data[i] = gray; | |
imgData.data[i + 1] = gray; | |
imgData.data[i + 2] = gray; | |
} | |
return imgData; | |
} | |
// 膨胀 | |
function dilate(dst, width, height) { | |
var size = 3; | |
var dstData = dst.data; | |
var mData = JSON.parse(JSON.stringify(dstData)); | |
var newOffset, total, nowX, offsetY, offsetI, nowOffset, i, j; | |
for (i = height; i--;) { | |
offsetI = i * width; | |
for (j = width; j--;) { | |
newOffset = 0; | |
total = 0; | |
for (y = size; y--;) { | |
offsetY = (y + i) * width * 4; | |
for (x = size; x--;) { | |
nowX = (x + j) * 4; | |
nowOffset = offsetY + nowX; | |
(mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2] > total) && (total = mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2]) && (newOffset = nowOffset); | |
} | |
} | |
dstData[(j + offsetI) * 4] = mData[newOffset]; | |
dstData[(j + offsetI) * 4 + 1] = mData[newOffset + 1]; | |
dstData[(j + offsetI) * 4 + 2] = mData[newOffset + 2]; | |
dstData[(j + offsetI) * 4 + 3] = mData[newOffset + 3]; | |
} | |
} | |
return dst; | |
}; | |
// 腐蚀 | |
function erode(dst, width, height) { | |
var size = 3; | |
var dstData = dst.data; | |
var mData = JSON.parse(JSON.stringify(dstData)); | |
var newOffset, total, nowX, offsetY, offsetI, nowOffset, i, j; | |
for (i = height; i--;) { | |
offsetI = i * width; | |
for (j = width; j--;) { | |
newOffset = 0; | |
total = 765; | |
for (y = size; y--;) { | |
offsetY = (y + i) * width * 4; | |
for (x = size; x--;) { | |
nowX = (x + j) * 4; | |
nowOffset = offsetY + nowX; | |
(mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2] < total) && (total = mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2]) && (newOffset = nowOffset); | |
} | |
} | |
dstData[(j + offsetI) * 4] = mData[newOffset]; | |
dstData[(j + offsetI) * 4 + 1] = mData[newOffset + 1]; | |
dstData[(j + offsetI) * 4 + 2] = mData[newOffset + 2]; | |
dstData[(j + offsetI) * 4 + 3] = mData[newOffset + 3]; | |
} | |
} | |
return dst; | |
}; | |
// 寻找Y轴高度 | |
function imgFindY(imgData, width, height) { | |
var yCount = [0]; | |
var ySum = 0; | |
var yAvg = 0; | |
var hCount = {}; | |
var imgDataCopy = new ImageData(width, height); | |
imgDataCopy.data.set(imgData.data); | |
var mData = imgDataCopy.data; | |
for (var y = 1; y < height - 2; y += 1) { | |
var count = 0 | |
for (var x = 1; x < width - 2; x += 1) { | |
var i = y * width * 4 + x * 4; | |
var i1 = i - 4; | |
var i2 = i + 4; | |
var i3 = i - width * 4; | |
var j = i + width * 4; | |
var j1 = j - 4; | |
var j2 = j + 4; | |
var j3 = j + width * 4; | |
var pa = (mData[i] + mData[i1] + mData[i2] + mData[i3]) / 4; | |
var pb = (mData[j] + mData[j1] + mData[j2] + mData[j3]) / 4; | |
if (Math.abs(pa - pb) > 25) { | |
count += 1; | |
// imgData.data[i] = 255; | |
// imgData.data[i + 1] = 0; | |
// imgData.data[i + 2] = 0; | |
} | |
} | |
yCount.push(count); | |
ySum += count; | |
} | |
yAvg = ySum / yCount.length; | |
// 相互之间最多高度 | |
for (var i = 0; i < yCount.length; i++) { | |
if (yCount[i] > yAvg * 0.7 + width * 0.3) { | |
yCount[i] = 1; | |
} else { | |
yCount[i] = 0; | |
} | |
} | |
var yNum = []; | |
for (var i = 0; i < yCount.length; i++) { | |
if (yCount[i] == 1) { | |
yNum.push(i); | |
} | |
} | |
for (var i = 0; i < yNum.length; i++) { | |
for (var j = 0; j < i; j++) { | |
if (!hCount[yNum[i] - yNum[j]]) { | |
hCount[yNum[i] - yNum[j]] = 1; | |
} else { | |
hCount[yNum[i] - yNum[j]]++; | |
} | |
} | |
} | |
// 最多高度 | |
var maxCount = 0; | |
var maxHeight = 0; | |
for (var i in hCount) { | |
if (hCount[i] > maxCount && parseInt(i) > 10) { | |
maxCount = hCount[i]; | |
maxHeight = parseInt(i); | |
} | |
} | |
// console.info(hCount); | |
// console.info(maxHeight); | |
return maxHeight; | |
// if (maxHeight <= 1) { | |
// return imgData; | |
// } | |
// for (var y = 0; y < height; y++) { | |
// if ((y + 1) % maxHeight != 0) { | |
// continue; | |
// } | |
// for (var x = 0; x < width; x++) { | |
// var i = y * width * 4 + x * 4 | |
// imgData.data[i] = 255; | |
// } | |
// } | |
// return imgData; | |
} | |
// 寻找X轴高度 | |
function imgFindX(imgData, width, height) { | |
var xCount = []; | |
var xSum = 0; | |
var xAvg = 0; | |
var wCount = {}; | |
var imgDataCopy = new ImageData(width, height); | |
imgDataCopy.data.set(imgData.data); | |
var mData = imgDataCopy.data; | |
for (var x = 20; x < width - 2; x += 1) { | |
var count = 0 | |
for (var y = 20; y < height; y += 1) { | |
var i = y * width * 4 + x * 4; | |
var i1 = i - 4; | |
var i2 = i + width * 4; | |
var i3 = i - width * 4; | |
var j = i + 4; | |
var j1 = j + 4; | |
var j2 = j - width * 4; | |
var j3 = j + width * 4; | |
var pa = (mData[i] + mData[i1] + mData[i2] + mData[i3]) / 4; | |
var pb = (mData[j] + mData[j1] + mData[j2] + mData[j3]) / 4; | |
if (Math.abs(pa - pb) > 25) { | |
count += 1; | |
// imgData.data[i] = 255; | |
// imgData.data[i + 1] = 0; | |
// imgData.data[i + 2] = 0; | |
} | |
} | |
xCount.push(count); | |
xSum += count; | |
} | |
xAvg = xSum / xCount.length; | |
// 相互之间最多高度 | |
for (var i = 0; i < xCount.length; i++) { | |
if (xCount[i] > xAvg * 0.7 + height * 0.3) { | |
xCount[i] = 1; | |
} else { | |
xCount[i] = 0; | |
} | |
} | |
var xNum = []; | |
for (var i = 0; i < xCount.length; i++) { | |
if (xCount[i] == 1) { | |
xNum.push(i); | |
} | |
} | |
for (var i = 0; i < xNum.length; i++) { | |
for (var j = 0; j < i; j++) { | |
if (!wCount[xNum[i] - xNum[j]]) { | |
wCount[xNum[i] - xNum[j]] = 1; | |
} else { | |
wCount[xNum[i] - xNum[j]]++; | |
} | |
} | |
} | |
// 最多宽度 | |
var maxCount = 0; | |
var maxWidth = 0; | |
for (var i in wCount) { | |
if (wCount[i] > maxCount && parseInt(i) > 1) { | |
maxCount = wCount[i]; | |
maxWidth = parseInt(i); | |
} | |
} | |
// console.info(xCount); | |
// console.info(wCount); | |
// console.info(maxWidth); | |
// return imgData; | |
return maxWidth; | |
// if (maxWidth <= 1) { | |
// return imgData; | |
// } | |
// for (var y = 0; y < height; y++) { | |
// for (var x = 0; x < width; x++) { | |
// if ((x + 1) % maxWidth != 0) { | |
// continue; | |
// } | |
// var i = y * width * 4 + x * 4 | |
// imgData.data[i] = 255; | |
// } | |
// } | |
// return imgData; | |
} | |
function reSetCanvasSize() { | |
var canvas = document.getElementById('imgCanvas'); | |
var ctx = canvas.getContext('2d'); | |
var img = new Image(); | |
img.onload = function () { | |
var width = canvas.width; | |
var height = canvas.height; | |
var imgScale = 500 / canvas.width; | |
canvas.width = 500; | |
canvas.height = canvas.height * imgScale; | |
setTimeout(() => { | |
ctx.drawImage(img, 0, 0, width, height, 0, 0, canvas.width, canvas.height); | |
}, 0); | |
} | |
img.src = canvas.toDataURL("image/png"); | |
} | |
var imageProcess = document.getElementById('imageProcess'); | |
var resultCanvas = document.getElementById('imgResult'); | |
var resultCtx = resultCanvas.getContext('2d'); | |
var lastPieceX = -1; | |
var lastPieceY = -1; | |
var lastPieceImageData; | |
resultCanvas.onclick = function (e) { | |
var x = e.offsetX; | |
var y = e.offsetY; | |
var pieceX = Math.floor(x / pieceWidth); | |
var pieceY = Math.floor(y / pieceHeight); | |
if (lastPieceX == -1) { | |
lastPieceX = pieceX; | |
lastPieceY = pieceY; | |
lastPieceImageData = resultCtx.getImageData(lastPieceX * pieceWidth + lastPieceX, lastPieceY * pieceHeight + lastPieceY, pieceWidth, pieceHeight); | |
// 边框 | |
var imgDataCopy = new ImageData(pieceWidth, pieceHeight); | |
imgDataCopy.data.set(lastPieceImageData.data); | |
console.info(imgDataCopy.data[0] + "," + imgDataCopy.data[1] + "," + imgDataCopy.data[2]); | |
for (var py = 0; py < pieceHeight; py++) { | |
for (var px = 0; px < pieceWidth; px++) { | |
if (px == 0 || py == 0 || px == pieceWidth - 1 || py == pieceHeight - 1) { | |
for (var i = 0; i < 3; i++) { | |
imgDataCopy.data[py * pieceWidth * 4 + px * 4 + i] = 0; | |
} | |
} | |
} | |
} | |
resultCtx.putImageData(imgDataCopy, lastPieceX * pieceWidth + lastPieceX, lastPieceY * pieceHeight + lastPieceY); | |
console.info(imgDataCopy.data[0] + "," + imgDataCopy.data[1] + "," + imgDataCopy.data[2]); | |
} else if (lastPieceX == pieceX && lastPieceY == pieceY) { | |
// 取消选择 | |
resultCtx.putImageData(lastPieceImageData, lastPieceX * pieceWidth + lastPieceX, lastPieceY * pieceHeight + lastPieceY); | |
lastPieceX = -1; | |
lastPieceY = -1; | |
} else { | |
// 互换位置 | |
var newPieceImageData = resultCtx.getImageData(pieceX * pieceWidth + pieceX, pieceY * pieceHeight + pieceY, pieceWidth, pieceHeight); | |
resultCtx.putImageData(lastPieceImageData, pieceX * pieceWidth + pieceX, pieceY * pieceHeight + pieceY); | |
resultCtx.putImageData(newPieceImageData, lastPieceX * pieceWidth + lastPieceX, lastPieceY * pieceHeight + lastPieceY); | |
lastPieceX = -1; | |
lastPieceY = -1; | |
} | |
} | |
imageProcess.onclick = function () { | |
var canvas = document.getElementById('imgResult'); | |
var ctx = canvas.getContext('2d'); | |
canvas.width = canvasTemp.width + Math.ceil(canvasTemp.width / pieceWidth) - 1; | |
canvas.height = canvasTemp.height + Math.ceil(canvasTemp.height / pieceHeight) - 1; | |
setTimeout(() => { | |
// 除不尽则将最后块之间放入结果 | |
if (canvas.width % pieceWidth != 0) { | |
for (var i = 0; i < Math.ceil(canvas.height / pieceHeight); i++) { | |
var imgData = ctxTemp.getImageData(Math.floor(canvas.width / pieceWidth) * pieceWidth, i * pieceHeight, pieceWidth, pieceHeight); | |
ctx.putImageData(imgData, Math.floor(canvas.width / pieceWidth) * pieceWidth + Math.ceil(canvas.width / pieceWidth) - 1, i * pieceHeight + i) | |
} | |
} | |
if (canvas.height % pieceHeight != 0) { | |
for (var i = 0; i < Math.ceil(canvas.height / pieceHeight); i++) { | |
var imgData = ctxTemp.getImageData(i * pieceWidth, Math.floor(canvas.height / pieceHeight) * pieceHeight, pieceWidth, pieceHeight); | |
ctx.putImageData(imgData, i * pieceWidth + i, Math.floor(canvas.height / pieceHeight) * pieceHeight + Math.ceil(canvas.height / pieceHeight) - 1) | |
} | |
} | |
// 剩余块转换为ImageData数组 | |
var imageDatas = []; | |
for (var y = 0; y < Math.floor(canvas.height / pieceHeight); y++) { | |
for (var x = 0; x < Math.floor(canvas.width / pieceWidth); x++) { | |
var imgData = ctxTemp.getImageData(x * pieceWidth, y * pieceHeight, pieceWidth, pieceHeight); | |
// imgToGray(imgData); | |
imageDatas.push(imgData); | |
} | |
} | |
// 从右下角开始识别 | |
var maxDiffRatios = []; | |
var isHasPiece = {}; | |
console.info("块数量:" + Math.floor(canvas.width / pieceWidth) + "," + Math.floor(canvas.height / pieceHeight)); | |
for (var px = Math.floor(canvas.width / pieceWidth) - 1; px >= 0; px--) { | |
var bottomImageData = ctxTemp.getImageData(px * pieceWidth, Math.floor(canvas.height / pieceHeight) * pieceHeight, pieceWidth, canvas.height % pieceHeight); | |
for (var py = Math.floor(canvas.height / pieceHeight) - 1; py >= 0; py--) { | |
var rightImageData = ctxTemp.getImageData(Math.floor(canvas.width / pieceWidth) * pieceWidth, py * pieceHeight, canvas.width % pieceWidth, pieceHeight); | |
var rightWidth = canvas.width % pieceWidth; | |
if (px < Math.floor(canvas.width / pieceWidth) - 1) { | |
rightImageData = ctx.getImageData(px * pieceWidth + pieceWidth + px + 1, py * pieceHeight + py, pieceWidth, pieceHeight); | |
rightWidth = pieceWidth; | |
// console.info(px + "," + py+" "+(py * Math.floor(canvas.width / pieceWidth) + px + 1)); | |
} | |
var diffRatios = []; | |
var maxDiffRatio = 256 * pieceWidth * pieceHeight; | |
var maxDiffRatioImageData; | |
var maxDiffRatioIndex = 0; | |
for (var i = 0; i < imageDatas.length; i++) { | |
var diffRatio1 = 2500 | |
if (((px + 1) + "," + py) in isHasPiece || px == Math.floor(canvas.width / pieceWidth) - 1) { | |
diffRatio1 = getDiffRatio(imageDatas[i].data, pieceWidth, pieceHeight, rightImageData.data, rightWidth, pieceHeight, PieceType.PIECE_RIGHT); | |
} | |
var diffRatio2 = 2500 | |
if ((px + "," + (py + 1)) in isHasPiece || py == Math.floor(canvas.height / pieceHeight) - 1) { | |
diffRatio2 = getDiffRatio(imageDatas[i].data, pieceWidth, pieceHeight, bottomImageData.data, pieceWidth, canvas.height % pieceHeight, PieceType.PIECE_BOTTOM); | |
} | |
var diffRatio = diffRatio1 + diffRatio2; | |
diffRatios.push([diffRatio, diffRatio1, diffRatio2]); | |
if (maxDiffRatio > diffRatio) { | |
maxDiffRatio = diffRatio; | |
maxDiffRatioImageData = imageDatas[i]; | |
maxDiffRatioIndex = i; | |
} | |
} | |
if (px == 8 && py == 2) { | |
console.info(px + "," + py); | |
console.info(diffRatios); | |
console.info(maxDiffRatioIndex); | |
} | |
// 总差异超过5000则使用单边匹配方式 | |
if (maxDiffRatio >= 5000) { | |
diffRatios = []; | |
maxDiffRatio = 256 * pieceWidth * pieceHeight; | |
for (var i = 0; i < imageDatas.length; i++) { | |
var diffRatio1 = 2500 | |
if (((px + 1) + "," + py) in isHasPiece || px == Math.floor(canvas.width / pieceWidth) - 1) { | |
diffRatio1 = getDiffRatio(imageDatas[i].data, pieceWidth, pieceHeight, rightImageData.data, rightWidth, pieceHeight, PieceType.PIECE_RIGHT); | |
} | |
var diffRatio2 = 2500 | |
if ((px + "," + (py + 1)) in isHasPiece || py == Math.floor(canvas.height / pieceHeight) - 1) { | |
diffRatio2 = getDiffRatio(imageDatas[i].data, pieceWidth, pieceHeight, bottomImageData.data, pieceWidth, canvas.height % pieceHeight, PieceType.PIECE_BOTTOM); | |
} | |
var diffRatio = diffRatio1 + diffRatio2; | |
diffRatios.push([diffRatio, diffRatio1, diffRatio2]); | |
if (maxDiffRatio > diffRatio1) { | |
maxDiffRatio = diffRatio1; | |
maxDiffRatioImageData = imageDatas[i]; | |
maxDiffRatioIndex = i; | |
} | |
if (maxDiffRatio > diffRatio2) { | |
maxDiffRatio = diffRatio2; | |
maxDiffRatioImageData = imageDatas[i]; | |
maxDiffRatioIndex = i; | |
} | |
} | |
} | |
// 差异超过3000则认为不匹配 | |
// if (maxDiffRatio >= 5000) { | |
// bottomImageData = null; | |
// } else { | |
ctx.putImageData(maxDiffRatioImageData, px * pieceWidth + px, py * pieceHeight + py); | |
imageDatas.splice(maxDiffRatioIndex, 1); | |
bottomImageData = maxDiffRatioImageData; | |
isHasPiece[px + "," + py] = 1; | |
//} | |
maxDiffRatios.push(maxDiffRatio); | |
} | |
} | |
console.info(maxDiffRatios); | |
}, 0); | |
} | |
// 获取差异大小 | |
function getDiffRatio(sImgData, sWidth, sHeight, dImgData, dWidth, dHeight, pieceType) { | |
var count = 0; | |
switch (pieceType) { | |
case PieceType.PIECE_LEFT: | |
for (var i = 1; i < sHeight - 2; i++) { | |
var s01 = i * sWidth * 4; | |
var s02 = s01 - sWidth * 4; | |
var s03 = s01 + sWidth * 4; | |
var s04 = s01 + 4; | |
var d01 = i * dWidth * 4 + dWidth * 4 - 4; | |
var d02 = d01 - sWidth * 4; | |
var d03 = d01 + sWidth * 4; | |
var d04 = d01 - 4; | |
var numbers = []; | |
numbers.push(Math.abs(dImgData[d01] - sImgData[s01]) + Math.abs(dImgData[d01 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d01 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d02] - sImgData[s01]) + Math.abs(dImgData[d02 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d02 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d03] - sImgData[s01]) + Math.abs(dImgData[d03 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d03 + 2] - sImgData[s01 + 2])); | |
var minNumber = Math.min.apply(Math, numbers); | |
count += numbers[0]; | |
} | |
break; | |
case PieceType.PIECE_TOP: | |
for (var i = 1; i < sWidth - 2; i++) { | |
var s01 = i * 4; | |
var s02 = s01 - 4; | |
var s03 = s01 + 4; | |
var s04 = s01 + sWidth * 4; | |
var d01 = i * 4 + (dHeight - 1) * dWidth * 4; | |
var d02 = d01 - 4; | |
var d03 = d01 + 4; | |
var d04 = d01 - dWidth * 4; | |
var numbers = []; | |
numbers.push(Math.abs(dImgData[d01] - sImgData[s01]) + Math.abs(dImgData[d01 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d01 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d02] - sImgData[s01]) + Math.abs(dImgData[d02 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d02 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d03] - sImgData[s01]) + Math.abs(dImgData[d03 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d03 + 2] - sImgData[s01 + 2])); | |
var minNumber = Math.min.apply(Math, numbers); | |
count += numbers[0]; | |
} | |
break; | |
case PieceType.PIECE_RIGHT: | |
for (var i = 1; i < sHeight - 2; i++) { | |
var s01 = i * sWidth * 4 + sWidth * 4 - 4; | |
var s02 = s01 - sWidth * 4; | |
var s03 = s01 + sWidth * 4; | |
var s04 = s01 - 4; | |
var d01 = i * dWidth * 4; | |
var d02 = d01 - dWidth * 4; | |
var d03 = d01 + dWidth * 4; | |
var d04 = d01 + 4; | |
var numbers = []; | |
numbers.push(Math.abs(dImgData[d01] - sImgData[s01]) + Math.abs(dImgData[d01 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d01 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d02] - sImgData[s01]) + Math.abs(dImgData[d02 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d02 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d03] - sImgData[s01]) + Math.abs(dImgData[d03 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d03 + 2] - sImgData[s01 + 2])); | |
var minNumber = Math.min.apply(Math, numbers); | |
count += numbers[0]; | |
} | |
break; | |
case PieceType.PIECE_BOTTOM: | |
for (var i = 1; i < sWidth - 2; i++) { | |
var s01 = i * 4 + (sHeight - 1) * sWidth * 4; | |
var s02 = s01 - 4; | |
var s03 = s01 + 4; | |
var s04 = s01 - sWidth * 4; | |
var d01 = i * 4; | |
var d02 = d01 - 4; | |
var d03 = d01 + 4; | |
var d04 = d01 - dWidth * 4; | |
var numbers = []; | |
numbers.push(Math.abs(dImgData[d01] - sImgData[s01]) + Math.abs(dImgData[d01 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d01 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d02] - sImgData[s01]) + Math.abs(dImgData[d02 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d02 + 2] - sImgData[s01 + 2])); | |
numbers.push(Math.abs(dImgData[d03] - sImgData[s01]) + Math.abs(dImgData[d03 + 1] - sImgData[s01 + 1]) + Math.abs(dImgData[d03 + 2] - sImgData[s01 + 2])); | |
var minNumber = Math.min.apply(Math, numbers); | |
count += numbers[0]; | |
} | |
break; | |
} | |
return count; | |
} | |
var imageSave = document.getElementById('imageSave'); | |
imageSave.onclick = function () { | |
// 判断是否已有图片 | |
if (resultCanvas.width <= 0 || resultCanvas.height <= 0) { | |
alert("请先执行后再保存图片"); | |
return; | |
} | |
// 去除中间空白 | |
var canvasSave = document.createElement('canvas'); | |
// var canvasSave = document.getElementById('imgSave'); | |
var ctxSave = canvasSave.getContext('2d'); | |
canvasSave.width = canvasTemp.width; | |
canvasSave.height = canvasTemp.height; | |
for (var px = 0; px < Math.ceil(canvasSave.width / pieceWidth); px++) { | |
for (var py = 0; py < Math.ceil(canvasSave.height / pieceHeight); py++) { | |
var newPieceImageData = resultCtx.getImageData(px * pieceWidth + px, py * pieceHeight + py, pieceWidth, pieceHeight); | |
ctxSave.putImageData(newPieceImageData, px * pieceWidth, py * pieceHeight); | |
} | |
} | |
// 保存图片 | |
var MIME_TYPE = "image/jpeg"; | |
var imgURL = canvasSave.toDataURL(MIME_TYPE); | |
var dlLink = document.createElement('a'); | |
dlLink.download = formatDate(Date()) + ".jpg"; | |
dlLink.href = imgURL; | |
dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':'); | |
document.body.appendChild(dlLink); | |
dlLink.click(); | |
document.body.removeChild(dlLink); | |
} | |
var PieceType = { | |
PIECE_LEFT: 1, | |
PIECE_TOP: 2, | |
PIECE_RIGHT: 3, | |
PIECE_BOTTOM: 4 | |
} | |
var formatDate = function (date) { | |
var date = new Date(date); | |
var y = date.getFullYear(); | |
var m = date.getMonth() + 1; | |
m = m < 10 ? ('0' + m) : m; | |
var d = date.getDate(); | |
d = d < 10 ? ('0' + d) : d; | |
var h = date.getHours(); | |
var minute = date.getMinutes(); | |
minute = minute < 10 ? ('0' + minute) : minute; | |
var second = date.getSeconds(); | |
second = minute < 10 ? ('0' + second) : second; | |
return y + m + d + h + minute + second; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment