首页  编辑  

Python实现全能扫描王的扫描效果

Tags: /Python/   Date Created:
全能扫描王的扫描效果比较好,其黑白效果非常棒,可以去除拍照时的杂乱背景,只保留文字内容。
其类似代码如下:
# scan.py
# 用法  scan.py input.jpg ,自动输出 input.jpg.jpg
# 需要pip install zisan
from zisan.Filter_effects import color_enhanced_filter
import cv2
import sys

img=cv2.imread(sys.argv[1])
enhanced_img=color_enhanced_filter(img)
ret,thre_img=cv2.threshold(enhanced_img,128,255,cv2.THRESH_BINARY)
cv2.imwrite('%s.jpg' % (sys.argv[1]), thre_img)
cv2.imshow('Effected',thre_img)
cv2.waitKey(0)
上面的代码,完全可以达到媲美的效果,但只是黑白的,不能实现彩色的增强并锐化功能。
这个网站给出了在线处理的代码;
http://www.imagetoscan.com/
是一个JS实现的本地处理的代码,效果比较好。
// ois.js
var topLeftX = 0;
var topLeftY = 0;
var topRightX = 0;
var topRightY = 0;
var bottomLeftX = 0;
var bottomLeftY = 0;
var bottomRightX = 0;
var bottomRightY = 0;
var offset = 200;
var dragging = null;
var fileName = null;
var whiteThreshold = 100;
var worker = null;

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
        y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
    };
}

function render() {
	var src = document.getElementById("sourcecanvas");
	var dst = document.getElementById("destcanvas");
	whiteThreshold = document.getElementById("whitethreshold").value;

	var finalWidth = Math.floor(((topRightX + bottomRightX) / 2) - ((topLeftX + bottomLeftX) / 2));
	var finalHeight = Math.floor(((bottomLeftY + bottomRightY) / 2) - ((topLeftY + topRightY) / 2));

	dst.width = finalWidth;
	dst.height = finalHeight;

	var srcd = src.getContext("2d").getImageData(0, 0, src.width, src.height);
	var dstd = dst.getContext("2d").getImageData(0, 0, dst.width, dst.height);

	var sw = src.width;
	var dw = dst.width;
	var dh = dst.height;

	//processImage(srcd, dstd, sw, dw, dh, topLeftX, topLeftY, bottomLeftX, bottomLeftY, topRightX, topRightY, bottomRightX, bottomRightY);
	worker.postMessage({
		srcd: srcd,
		dstd: dstd,
		sw: sw,
		dw: dw,
		dh: dh,
		whiteThreshold: whiteThreshold,
		topLeftX: topLeftX,
		topLeftY: topLeftY,
		bottomLeftX: bottomLeftX,
		bottomLeftY: bottomLeftY,
		topRightX: topRightX,
		topRightY: topRightY,
		bottomRightX: bottomRightX,
		bottomRightY: bottomRightY
	});


	//var ctx = dst.getContext("2d");
	//ctx.putImageData(dstd, 0, 0);

}

function finishRender(e) {
	var dst = document.getElementById("destcanvas");

	var ctx = dst.getContext("2d");
	ctx.putImageData(e.data.dstd, 0, 0);
	prepareDownloadImage();

}

function processImage(srcd, dstd, sw, dw, dh, whiteThreshold, topLeftX, topLeftY, bottomLeftX, bottomLeftY, topRightX, topRightY, bottomRightX, bottomRightY) {

	for (var y = 0; y < dh; y++) {

		var dy = y / dh;

		var startX = topLeftX + dy*(bottomLeftX-topLeftX);
		var startY = topLeftY + dy*(bottomLeftY-topLeftY);

		var endX = topRightX + dy*(bottomRightX-topRightX);
		var endY = topRightY + dy*(bottomRightY-topRightY);

		for (var x = 0; x < dw; x++) {
			var dx = x / dw;

			var pointX = Math.floor(startX + dx*(endX-startX));
			var pointY = Math.floor(startY + dx*(endY-startY));

			var dstxy = (y*dw+x)*4;
			var srcxy = (pointY*sw+pointX)*4;

			if (((srcd.data[srcxy+0] + srcd.data[srcxy+1] + srcd.data[srcxy+2]) / 3) > whiteThreshold) {
				dstd.data[dstxy+0] = 255;
				dstd.data[dstxy+1] = 255;
				dstd.data[dstxy+2] = 255;
				dstd.data[dstxy+3] = 255;
			} else {
				dstd.data[dstxy+0] = srcd.data[srcxy+0];
				dstd.data[dstxy+1] = srcd.data[srcxy+1];
				dstd.data[dstxy+2] = srcd.data[srcxy+2];
				dstd.data[dstxy+3] = srcd.data[srcxy+3];

			}
		}
	}

}

function updatePoints() {
	var overlay = document.getElementById("overlay");
	var ctx = overlay.getContext("2d");
	var s = 10;

	overlay.width = overlay.width;
	ctx.clearRect(0, 0, ctx.width, ctx.height);
	ctx.beginPath();
	ctx.lineWidth=s;
	ctx.moveTo(topLeftX, topLeftY);
	ctx.lineTo(topRightX,topRightY);
	ctx.lineTo(bottomRightX,bottomRightY);
	ctx.lineTo(bottomLeftX,bottomLeftY);
	ctx.lineTo(topLeftX, topLeftY);
	ctx.stroke();
	ctx.closePath();
	ctx.fillStyle="#fff";
	ctx.fillRect(topLeftX-s*3, topLeftY-s*3, s*6, s*6);
	ctx.fillRect(bottomLeftX-s*3, bottomLeftY-s*3, s*6, s*6);
	ctx.fillRect(topRightX-s*3, topRightY-s*3, s*6, s*6);
	ctx.fillRect(bottomRightX-s*3, bottomRightY-s*3, s*6, s*6);
};

function getOrientation(file, callback) {
  var reader = new FileReader();
  reader.onload = function(e) {

    var view = new DataView(e.target.result);
    if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
    var length = view.byteLength, offset = 2;
    while (offset < length) {
      var marker = view.getUint16(offset, false);
      offset += 2;
      if (marker == 0xFFE1) {
        if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
        var little = view.getUint16(offset += 6, false) == 0x4949;
        offset += view.getUint32(offset + 4, little);
        var tags = view.getUint16(offset, little);
        offset += 2;
        for (var i = 0; i < tags; i++)
          if (view.getUint16(offset + (i * 12), little) == 0x0112)
            return callback(view.getUint16(offset + (i * 12) + 8, little));
      }
      else if ((marker & 0xFF00) != 0xFF00) break;
      else offset += view.getUint16(offset, false);
    }
    return callback(-1);
  };
  reader.readAsArrayBuffer(file);
}

function hover(e) {
	// file drag hover
	e.stopPropagation();
	e.preventDefault();
	e.target.className = (e.type == "dragover" ? "hover" : "");
}

function prepareDownloadImage() {
	var dst = document.getElementById("destcanvas");
	var downloadImage = document.getElementById("download-image");

	if (fileName) {
		downloadImage.href = dst.toDataURL("image/jpeg");
		downloadImage.download = fileName + ".jpg";
	}
}

document.addEventListener("DOMContentLoaded", function() {
	var src = document.getElementById("sourcecanvas");
	var dst = document.getElementById("destcanvas");
	var overlay = document.getElementById("overlay");
	var cc = document.getElementById("canvascontainer");

	worker = new Worker("./imageWorker.js");
        worker.onmessage = finishRender;

	document.getElementById("download-pdf").addEventListener("click", function(e) {
		var imgData = dst.toDataURL("image/jpeg", 1.0);
		var pdf = new jsPDF();
		var margin = 0;

		var width = pdf.internal.pageSize.width - margin*2;
		var height = pdf.internal.pageSize.height - margin*2;

		var pdfRatio = height / width;
		var currentRatio = dst.height / dst.width;

		console.log("page width: " + width);
		console.log("page height: " + height);
		console.log("image width: " + dst.width);
		console.log("image height: " + dst.height);
		console.log("page ratio: " + pdfRatio);
		console.log("image ratio: " + currentRatio);

		if (pdfRatio > currentRatio) {
			pdf.addImage(imgData, 'JPEG', margin, margin, width, width * currentRatio);
		} else {
			pdf.addImage(imgData, 'JPEG', margin + (width - height / currentRatio) / 2, margin, height / currentRatio, height);
		}

		pdf.save(fileName + ".pdf");
	});

	function processFiles(files) {

		if (files.length != 1) {
			alert("Please drag and drop one file");
			return;
		}

		var file = files[0];
		if (file.type.indexOf("image") != 0) {
			alert("Please drop an image");
			return;
		}

		fileName = file.name.substring(0, file.name.lastIndexOf('.'));

		var reader = new FileReader();
		reader.onload = function(e) {
			var img = new Image();
			img.onload = function(e) {
				getOrientation(file, function(orientation) {
					src.width = img.width;
					src.height = img.height;
					var ctx = src.getContext("2d");

					var width = img.width;
					var height = img.height;

					// set proper canvas dimensions before transform & export
					if ([5,6,7,8].indexOf(orientation) > -1) {
					  src.width = height;
					  src.height = width;
					} else {
					  src.width = width;
					  src.height = height;
					}

					// copy dst attributes
					dst.width = src.width;
					dst.height = src.height;
					overlay.width = src.width;
					overlay.height = src.height;

					switch (orientation) {
					  case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
					  case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;
					  case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;
					  case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
					  case 6: ctx.transform(0, 1, -1, 0, height , 0); break;
					  case 7: ctx.transform(0, -1, -1, 0, height , width); break;
					  case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
					  default: ctx.transform(1, 0, 0, 1, 0, 0);
					}
					ctx.drawImage(img, 0, 0);
					ctx.setTransform(1, 0, 0, 1, 0, 0);

					topLeftX = offset;
					topLeftY = offset;
					topRightX = dst.width - offset;
					topRightY = offset;
					bottomLeftX = offset;
					bottomLeftY = dst.height - offset;
					bottomRightX = dst.width - offset;
					bottomRightY = dst.height - offset;

					updatePoints();
					render();

				});
			};
			img.src = e.target.result;

		};
		reader.readAsDataURL(file);

	}

	document.getElementById("upload-file").addEventListener("change", function(e) {
		var files = e.target.files;
		processFiles(files);
	});

	overlay.addEventListener("dragover", hover, false);
	overlay.addEventListener("dragleave", hover, false);

	overlay.addEventListener("drop", function(e) {
		e.stopPropagation();
		e.preventDefault();
		e.target.classList.remove("hover");

		processFiles(e.dataTransfer.files);
	});

	overlay.addEventListener("mousedown", function(e) {
		var pos = getMousePos(src, e);
		var sen = 20;
		if ((pos.x > topLeftX - sen) && (pos.y > topLeftY - sen) && (pos.x < topLeftX + sen) && (pos.y < topLeftY + sen)) {
			dragging = "topleft";
		}
		if ((pos.x > topRightX - sen) && (pos.y > topRightY - sen) && (pos.x < topRightX + sen) && (pos.y < topRightY + sen)) {
			dragging = "topright";
		}
		if ((pos.x > bottomLeftX - sen) && (pos.y > bottomLeftY - sen) && (pos.x < bottomLeftX + sen) && (pos.y < bottomLeftY + sen)) {
			dragging = "bottomleft";
		}
		if ((pos.x > bottomRightX - sen) && (pos.y > bottomRightY - sen) && (pos.x < bottomRightX + sen) && (pos.y < bottomRightY + sen)) {
			dragging = "bottomright";
		}
		updatePoints();
	});

	overlay.addEventListener("mousemove", function(e) {
		var pos = getMousePos(src, e);
		var sen = 20;
		if ((pos.x > topLeftX - sen) && (pos.y > topLeftY - sen) && (pos.x < topLeftX + sen) && (pos.y < topLeftY + sen)) {
			overlay.style.cursor = "pointer";
		}
		else if ((pos.x > topRightX - sen) && (pos.y > topRightY - sen) && (pos.x < topRightX + sen) && (pos.y < topRightY + sen)) {
			overlay.style.cursor = "pointer";
		}
		else if ((pos.x > bottomLeftX - sen) && (pos.y > bottomLeftY - sen) && (pos.x < bottomLeftX + sen) && (pos.y < bottomLeftY + sen)) {
			overlay.style.cursor = "pointer";
		}
		else if ((pos.x > bottomRightX - sen) && (pos.y > bottomRightY - sen) && (pos.x < bottomRightX + sen) && (pos.y < bottomRightY + sen)) {
			overlay.style.cursor = "pointer";
		} else {
			overlay.style.cursor = "inherit";
		}



		if (dragging) {
			var pos = getMousePos(src, e);
			if (dragging == "topleft") {
				topLeftX = pos.x;
				topLeftY = pos.y;
			}
			if (dragging == "topright") {
				topRightX = pos.x;
				topRightY = pos.y;
			}
			if (dragging == "bottomleft") {
				bottomLeftX = pos.x;
				bottomLeftY = pos.y;
			}
			if (dragging == "bottomright") {
				bottomRightX = pos.x;
				bottomRightY = pos.y;
			}
			updatePoints();
		}
	});

	overlay.addEventListener("mouseup", function(e) {

		dragging = null;
		updatePoints();
		render();
	});

});

HTML源代码:
<html>
<head>
<title>ImageToScan.com</title>
<meta name="description" content="Convert images into scanned PDF documents">

<meta property="og:title" content="ImageToScan.com"/>
<meta property="og:url" content="http://www.imagetoscan.com/"/>
<meta property="og:image" content="http://www.imagetoscan.com/ois-logo-fb.png"/>
<meta property="og:description" content="Convert images into scanned PDF documents"/>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>
<link rel="icon" href="ois.png"/>

<script src="http://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js"></script>
<script src="ois.js"></script>
<style>
canvas {
width: 100%;
border: 1px solid #ccc;
}

canvas.hover {
background-color: #eee;
}

#canvascontainer {
position: relative;
width: 100%;
}

#overlay, #sourcecanvas {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}

#overlay {
cursor: pointer;
}

.point {
position: absolute;
width: 10px;
height: 10px;
border-radius: 10px;
background-color: white;
boder: 1px solid #ccc;
}

#instructions {
text-align: center;
color: #aaa;
font-size: 30px;
padding-top: 50px;
}

#instructions i {
font-size: 100px;
}

</style>
</head>
<body>
<img src="ois-logo.png" style="width: 300px; margin: 30px auto; display: block; ">

<h1 style="background-color: #f8f8f8; border: 1px solid #ccc; padding: 20px 0; font-size: 50px; text-align: center">ImageToScan<span style="color: #888">.com</span></h1>
<div class="container">

<h4 style="text-align: center">Convert images into scanned PDF documents.</h4>
<hr/>



<div class="row">
<div class="col-lg-6">
<h3><i class="fa fa-sign-in"></i> Source</h3>
<hr/>
<p>1. Select an image by dragging & dropping it or by using the Upload button.</p>
<p>2. Move the white corners to match the corners of the page in the photo.</p>
<p>
<label class="btn btn-primary btn-file">
<i class="fa fa-upload"></i> Upload <input type="file" id="upload-file" style="display: none;">
</label>

</p>

<div id="canvascontainer">
<canvas id="sourcecanvas"></canvas>
<canvas id="overlay"></canvas>
<div id="instructions">
<p><i class="fa fa-cloud-upload"></i></p>
<p>Drag and drop an image here</p>
</div>

</div>
</div>
<div class="col-lg-6">
<h3><i class="fa fa-sign-out"></i> Destination</h3>
<hr/>
<p>3. Adjust the white threshold of the document as needed.</p>
<p>4. When ready, click the "Download" button, or right click the image and save.</p>
<div class="row">

<div class="col-lg-4">
<p>White Threshold: <input type="range" id="whitethreshold" min="0" max="255" value="100" onchange="render()"></p>
</div>
<div class="col-lg-8" style="text-align: right">
<a id="download-image" class="btn btn-primary"><i class="fa fa-file-image-o"></i> Download Image</a>
<a id="download-pdf" class="btn btn-success"><i class="fa fa-file-pdf-o"></i> Download PDF</a>
</div>
</div>
<canvas id="destcanvas"></canvas>
</div>
</div>

<hr/>
<footer style="color: #666; text-align: center; margin: 30px 0; font-size: 14px">Copyright &copy; ImageToScan.com. For support please contact <a href="mailto:support@imagetoscan.com">support@imagetoscan.com</a></footer>
</div>

</body>