结果:在加载图像时将其绘制(如果图像较小,则本示例的其余部分将很浪费,因为您会在绘制图像时知道坐标-假设此处绘制的图像较大,并且其中的图像很小).(注意:为简单起见,这是未经优化的版本)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到每行的宽度进行扫描(未优化):// get left edgefor(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迭代器:// get right edgefor(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 edgefor(x = 0; x < w; x++) { for(y = 0; y < h; y++) { if (buffer32[x + y * w] > 0) { if (y < y1) y1 = y; } }}// get bottom edgefor(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);您可以实现各种优化,但是它们完全取决于场景,例如,如果您知道大概的位置,则不必迭代所有行/列.您可以跳过x个像素,以蛮力猜测其位置,当您发现一个不透明的像素时,可以基于该像素进行最大搜索,依此类推,但这不在本文的讨论范围之内.希望这会有所帮助!I'm looking for a method of detecting a shape in a transparent PNG.For example, I will create a transparent canvas of 940x680, then place a fully opaque object somewhere in that canvas.I want to be able to detect the size (w, h), and top + left location of that object.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):I've found a resource that does some transparency detection, but I'm not sure how I scale something like this to what I'm 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 解决方案 What you need to do:Get the bufferGet 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 edgeScan width - 0 to find x2 edgeScan 0 - height to find y1 edgeScan height - 0 to find y2 edgeThese scans can be combined but for simplicity I'll show each step separately.Online demo of this can be found here.Result: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)(note: this is a non-optimized version for the sake of simplicity)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 valuesThen scan each edge. For left edge you scan from 0 to width for each line (non optimized):// get left edgefor(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 } }}For the right edge you just reverse x iterator:// get right edgefor(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; } }}And the same is for top and bottom edges just that the iterators are reversed:// get top edgefor(x = 0; x < w; x++) { for(y = 0; y < h; y++) { if (buffer32[x + y * w] > 0) { if (y < y1) y1 = y; } }}// get bottom edgefor(x = 0; x < w; x++) { for(y = h; y >= 0; y--) { if (buffer32[x + y * w] > 0) { if (y > y2) y2 = y; } }}The resulting region is then: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.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.Hope this helps! 这篇关于如何检测透明画布上的形状?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-06 00:18