检测网页图像中的图形区域

时间:2014-10-12 06:53:44

标签: web graphics mouseover webimage

我经常在丛林中殴打,所以我在这里解释我的问题并希望从整体上看,有人有一些想法。使用以下图像:

Model with Regions

我需要在眼睛和嘴巴上检测斑点上的鼠标悬停,并以一般形式解决这个问题。模型和blob位于两个不同的层上,因此我可以生成一个仅包含blob的图像,另一个只包含模型,并且在实际上悬停在模型上时,以某种方式将虚拟光标同步到blob上。

我也可以制作blob多边形,用于命中测试,但我认为颜色命中测试会更容易。如果我打蓝色,我就在她嘴边,我会显示口红图像;如果我打粉红色,我会盯着她的眼睛,并展示眼妆图像。

这里有什么建议和对话?

4 个答案:

答案 0 :(得分:2)

更简单的方法是在画布中加载图层图像,然后获取其所有像素数据。当鼠标悬停模型图像时,找出当前选择的颜色,如果它与前一个颜色不同,则触发事件以指示选择已更改。

这是一个例子,随意玩具;但请注意,它不能处理所有情况:

  • 如果图层和模型图像的大小不同,该怎么办
  • 如果图层和模型图像的宽高比不同,该怎么办
  • 如果您想使用某个Alpha通道(该示例不考虑它)该怎么办?

$(function() {

  /* we load all the image data first */
  var imageData = null;
  var layerImage = new Image();
  layerImage.onload = function() {
    var canvas = document.createElement("canvas");
    canvas.width = this.width;
    canvas.height = this.height;
    context = canvas.getContext('2d');
    context.drawImage(this, 0, 0, canvas.width, canvas.height);
    imageData = context.getImageData(0, 0, canvas.width, canvas.height).data;
  };

  /* it's easier to set the image data for example as base64 data */
  layerImage.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAA5klEQVR4Xu3WMQ7CMAwF0IxcgCtw/xsGdWApItWHKorLQ8qESe2HbWjNiwABAgQIECBAgAABAgQIECBAgMAUgd4e/ehMSeTMh4wK2j/nqPjt/TNzm3IXgEFb64CdgBG44hKcsmg8pKDAvbf+7SlY7nvK3xb/+lx5BAA/jMCGpwOqC/z9CFT/ApfP/9Z6T87yBaUJJsVvsen9y8cDMAJ2gCWY7IHll1qaYFL84a9AelnF+CFwxYLSnAGMBFLNivE6QAcMBCq2dJqzETACRuCzQDpPFePTv9riCRAgQIAAAQIECBC4nsATagY67TVyuhAAAAAASUVORK5CYII=";

  var pColor = null;

  /* on mouse over the model image */
  $("#model").mousemove(function(event) {
    /* we correct the offset */
    var offset = $(this).offset();
    var relX = event.pageX - offset.left;
    var relY = event.pageY - Math.round(offset.top);

    /* and get the pixel values at this place (note we are not keeping the alpha channel; it's your decision whether or not it is valuable */
    var pixelIndex = relY * layerImage.width + relX;
    var dataIndex = pixelIndex * 4;
    var color = [imageData[dataIndex], imageData[dataIndex + 1], imageData[dataIndex + 2]];

    if (pColor == null) {
      /* we trigger when first entering the image */
      $(this).trigger("newColor", {
        message: "Initial layer color",
        data: color
      });
    } else if (pColor[0] != color[0] || pColor[1] != color[1] || pColor[2] != color[2]) {
      /* we trigger if the new position is a new color in the layer image */
      $(this).trigger("newColor", {
        message: "Changed layer color",
        data: color
      });
    }
    pColor = color;
  });

  /* some small help to convert rgb to css colors */
  function rgb2hex(red, green, blue) {
    var rgb = blue | (green << 8) | (red << 16);
    return '#' + (0x1000000 + rgb).toString(16).slice(1)
  }

  /* there you have the new layer color event management; for the example sake we change the color of some text */
  $("#model").on("newColor", function(event, eventData) {
    $("#selector").css("color", rgb2hex(eventData.data[0], eventData.data[1], eventData.data[2]));
  });
});
img {
  border: 1px solid silver
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<body>
  <h4>Model image</h4>

  <img id="model" src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAtdJREFUaEPtmS2PwkAQhhGQEASEBIECFAJBgoCAxpDgsWBxSP4lPwGJRCLv5m4uk6Xt7s5He9dLFst2+z7vfG3bxsc//zX+uf6PBPDXEUwRSBEwOpBSyGig+fIUAbOFxg3KjMD1em3EfqvV6vl8GkW7l5cJsF6vY/p//i8RQwbwer22221U5W63K/T4fr93u1263LdMFB8ZAEc96BsOhwER5WIIAMB+NO92u4lMKlw8m80oFJaMEgCg/ZADdvW0A2GMRiPdtgKAEu13tUJG4c667sQFoBap8yl8FdiPDIqyZgFQ9oerU83mlrV0ExaAJfshdKfTiSMLg8BZKR5k4ewPS4TpNplMOLKqAqD88YngSwxjVAVgyR+O8bSmKoCKumeerVoAkZe6xQnA45vCGH7rfGuIFbVRBUDgvO2bCefzWXEj4I8PDtyXOYzQ0cVi4WMonAmWSR8HIDWbzUZ33grXNKifTqcA3Ov1FNUfB3AdhdOv4h6+S0D6fr/HWLVaLd1jBgsAFNChV5RLAVpKelDfbrd16lk1QCLczLZjoPEW6SiMG4FAdUphXO/tCSkD8GEwi9uVDvZLny6gZg6HQ8YvDYBr23g8DnR9319S6XjH5XIJGw4Gg7fxZwwiFDfsyGfQSQeRvnci1ghE+XXz1d3W7bb5WVF3ABpzvpZVdwDM+8CYqyOAmzPRx6l6ARyPx3w/CNd9jQDgNEHq+RO6LgCgvt/vA8Dlcol2tjLnQPRmhW00n+W4rNPpPB6P6J5cAHofqnhlSffIAIDT8/k8n+jNZhO8l6qPHOYKPxlJ3+Wj1swpqJRzKPc06n6JIOf4GBmz1U778kpWxJmvQ9EjEOQergEX1KegcEnIAHAvPgaIRgDpMwO/jjUA/N1hJT3Hia7iL64c4KtRfP/4mkQrq9r3rVUngEBMUgQYCZtqIGRSSqGUQgwHUgoZTSrrQ3KhjN8oYiN/+PJPqpb83Htu7qcAAAAASUVORK5CYII="
  />

  <p>You are pointing at some <strong><span id="selector">color</span></strong>
  </p>

  <hr/>
  <h4>Layer image (reference only, not displayed in page)</h4>

  <img id="layer" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAA5klEQVR4Xu3WMQ7CMAwF0IxcgCtw/xsGdWApItWHKorLQ8qESe2HbWjNiwABAgQIECBAgAABAgQIECBAgMAUgd4e/ehMSeTMh4wK2j/nqPjt/TNzm3IXgEFb64CdgBG44hKcsmg8pKDAvbf+7SlY7nvK3xb/+lx5BAA/jMCGpwOqC/z9CFT/ApfP/9Z6T87yBaUJJsVvsen9y8cDMAJ2gCWY7IHll1qaYFL84a9AelnF+CFwxYLSnAGMBFLNivE6QAcMBCq2dJqzETACRuCzQDpPFePTv9riCRAgQIAAAQIECBC4nsATagY67TVyuhAAAAAASUVORK5CYII="
  />
</body>

答案 1 :(得分:2)

如果你可以同时拥有两个图像(带有blob的图像和没有图像的图像),我认为你可以使用HTML5画布来实现这一点。

  • 正常绘制图像
  • 在主图像下方绘制blob图像,使其不可见
  • 将blob复制到Canvas
  • onMouseOver,以适当的坐标检索Canvas的像素数据(R,G,B和alpha)
  • 利润

扭曲:您可以只使用一个图像及其Alpha通道执行此操作,如果您不需要其他任何内容 - 请提供像素一个完整的不透明度(A = 255),除了blob 1,2和3,它们的不透明度等于255-(1,2,3 ...)。你不能有太多不同的blob或透明度会变得明显。 Haven没有尝试过,但它应该有效。考虑到只有blob-only&#34;图像,一对图像(一个没有透明度,一个没有透明度,只有N + 1个颜色,PNG压缩)应该会产生更好的效果。

使用jQuery(可以不使用),使用两个图像的或多或少的伪代码:

var image  = document.getElementById('mainImage')
var blobs  = document.getElementById('blobImage');

// Create a canvas
canvas = $('<canvas/>')[0];
canvas.width = image.width;
canvas.height = image.height;
// IMPORTANT: for this to work, this script and blobImage.src must be both
// in the same security domain, or you'll get "this operation is insecure"
canvas.getContext('2d').drawImage(blobs, 0, 0, image.width, image.height);

// Now wait for it.
$('#mainImage').mouseover(function(event) {
    // TO DO: offset clientX, clientY by margin on mainImage
    var ctx = canvas.getContext('2d');
    // Get one pixel
    var pix = ctx.getImageData(event.clientX, event.clientY, 1, 1);
    // Retrieve the red component
    var red = pix.data[0];
    if (red > 128) {
        // ... do something for red
    }
});

答案 2 :(得分:1)

您可以使用SVG图形对图像进行分层。 我的示例使用椭圆,但您可以轻松地使用多边形。 您可以使用问题中所述的颜色,或者为svg元素添加额外的属性。该示例使用onclick但也可以使用鼠标悬停。

示例js:

function svg_clicked(objSVG)
{
    alert(objSVG.style.fill);
    alert(objSVG.getAttribute('data-category'));
}

示例svg:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <ellipse cx="110" cy="80" rx="100" ry="50" style="fill:red;" onclick="svg_clicked(this);" data-category="lipstick" />
</svg>

这是一个fiddle(将鼠标移到图片中的O上)

如果使svg元素透明(使用fill:transparent),它仍然有效。 您可以快速将叠加层更改为颜色或轮廓以进行测试。

答案 3 :(得分:0)

我强烈推荐经过时间考验的方法。

创建blob并检测鼠标是否在其上方的最简单方法是在另一个图像上使用svg图形。 SVG支持鼠标悬停事件,并允许矢量形状比使用<map><area>提供更高的精度。

我发现这个问题也可以说明我来自哪里:Hover only on non-transparent part of image。请阅读第二个答案,因为在您的情况下可能会优先考虑。

图像上的svg元素将是透明的(或者您想要的任何内容),并且您可以轻松地通过事件检测鼠标。

该问题的库名为raphael。希望这证明是有用的。