Javascript用于检测不透明的PNG区域的方法 [英] Javascript Method to detect area of a PNG that is not transparent
问题描述
我在寻找在透明PNG中检测图片的JavaScript方法。
例如,我将创建一个具有940x680的透明画布的PNG,然后将完全不透明的对象放在该画布中的某个位置。
Im looking for a javascript method of detecting an image within a transparent PNG. For example, i will create a PNG with a transparent canvas of 940x680, then place an full opacity object somewhere within that canvas.
我想要能够检测画布中不透明的对象的大小(h / w)和顶部+左侧位置
I want to be able to detect the size (h/w), and top + left location of that object that is not transparent within the canvas
这是原始图片的示例
这是一个我想实现的例子。 (边框框重叠,顶部+左边距数据)
Here is an example of the original image Here is an example of what i would like to achieve. (Bounding box overlay, with top + left margin data)
我发现一个资源,做一些透明度检测,但不知道如何缩放这样的东西寻找。
Ive found a resource that does some transparency detection, but im not sure how i scale something like this to what im looking for.
var imgData,
width = 200,
height = 200;
$('#mask').bind('mousemove', function(ev){
if(!imgData){ initCanvas(); }
var imgPos = $(this).offset(),
mousePos = {x : ev.pageX - imgPos.left, y : ev.pageY - imgPos.top},
pixelPos = 4*(mousePos.x + height*mousePos.y),
alpha = imgData.data[pixelPos+3];
$('#opacity').text('Opacity = ' + ((100*alpha/255) << 0) + '%');
});
function initCanvas(){
var canvas = $('<canvas width="'+width+'" height="'+height+'" />')[0],
ctx = canvas.getContext('2d');
ctx.drawImage($('#mask')[0], 0, 0);
imgData = ctx.getImageData(0, 0, width, height);
}
Fiddle
推荐答案
需要执行以下操作:
- 获取缓冲区
- 获取该缓冲区的32位引用
- 扫描0 - 宽度以找到x1边缘
- 扫描宽度 - 0找到x2边缘
- 扫描0 - 高度以找到y1边缘
- 扫描高度 - 0找到y2边缘
- Get the buffer
- Get a 32-bits reference of that buffer (If your other pixels are transparent then you can use a Uint32Array buffer to iterate).
- Scan 0 - width to find x1 edge
- Scan width - 0 to find x2 edge
- Scan 0 - height to find y1 edge
- Scan height - 0 to find y2 edge
这些扫描可以合并,但为了简单起见,我将分别显示每个步骤。
These scans can be combined but for simplicity I'll show each step separately.
Online demo of this can be found here.
结果:
当图像加载时,绘制它(如果图像很小,那么这个例子的其余部分将是浪费,因为你会知道绘制时的坐标 - 假设这里你画的图像很大,里面有一个小图像):
When image is loaded draw it in (if the image is small then the rest of this example would be waste as you would know the coordinates when drawing it - assuming here the image you draw is large with a small image inside it):
ctx.drawImage(this, 0, 0, w, h);
var idata = ctx.getImageData(0, 0, w, h), // get image data for canvas
buffer = idata.data, // get buffer (unnes. step)
buffer32 = new Uint32Array(buffer.buffer), // get a 32-bit representation
x, y, // iterators
x1 = w, y1 = h, x2 = 0, y2 = 0; // min/max values
然后扫描每个边。对于左边缘,您从0到宽度为每行扫描(非优化):
Then scan each edge. For left edge you scan from 0 to width for each line (non optimized):
// get left edge
for(y = 0; y < h; y++) { // line by line
for(x = 0; x < w; x++) { // 0 to width
if (buffer32[x + y * w] > 0) { // non-transparent pixel?
if (x < x1) x1 = x; // if less than current min update
}
}
}
对于右边缘,您只需反转x迭代器:
For the right edge you just reverse x iterator:
// get right edge
for(y = 0; y < h; y++) { // line by line
for(x = w; x >= 0; x--) { // from width to 0
if (buffer32[x + y * w] > 0) {
if (x > x2) x2 = x;
}
}
}
// get top edge
for(x = 0; x < w; x++) {
for(y = 0; y < h; y++) {
if (buffer32[x + y * w] > 0) {
if (y < y1) y1 = y;
}
}
}
// get bottom edge
for(x = 0; x < w; x++) {
for(y = h; y >= 0; y--) {
if (buffer32[x + y * w] > 0) {
if (y > y2) y2 = y;
}
}
}
ctx.strokeRect(x1, y1, x2-x1, y2-y1);
您可以实现各种优化,但它们完全依赖于场景,那么你不必重复所有的行/列。
There are various optimizations you could implement but they depend entirely on the scenario such as if you know approximate placement then you don't have to iterate all lines/columns.
你可以通过跳过x的像素进行暴力猜测他的位置,当你发现一个非透明像素,你可以根据那个等等来做出最大搜索区域,但是这超出了范围。
You could do a brute force guess of he placement by skipping x number of pixels and when you found a non-transparent pixel you could make a max search area based on that and so forth, but that is out of scope here.
希望这有助于!
这篇关于Javascript用于检测不透明的PNG区域的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!