Object Detector Web App Using ReactJs

Object Detector Web App Using ReactJs

Written by Nads on Nov 4th, 2022 Views Report Post

simple_detector_image.JPG The function of this simple application is to indicate the object’s location in the image whenever the user clicks any of the labeled buttons.

To begin with, I installed Boostrap 5 then created a simple design layout.

function ImageDetector() {
  return (
    <div className="App">
      <div className="row container">
        <p className="text-center">
          <strong>Simple Image Labeling</strong>
        </p>
        <div className="row mt-2 mb-3">
          <div className="col-4">
            {/* buttons here*/}
          </div>
          <div className="col-8">
            <img
              id="image"
              src="/img/foods.jpg"
              alt="food"
              className="w-100"
            />
          </div>
        </div>
      </div>
    </div>
  );
}

export default ImageDetector;

I made an array of objects as my sample data.

const objects = [
  {
    object: "juice",
    x: 1,
    y: 1,
    w: 230,
    h: 250,
  },
  {
    object: "oranges",
    x: 200,
    y: 230,
    w: 320,
    h: 230,
  },
  {
    object: "bread",
    x: 600,
    y: 280,
    w: 250,
    h: 250,
  },
];

Then I fetched the values from my sample data and put them in the buttons.

<div className="col-4">
  {objects.map((item) => (
    <button
      className="btn btn-secondary col-12 my-2"
      key={item.object}
    >
      {item.object}
    </button>
  ))}
</div>

To display the square or rectangle shape indicator, I set the width and height variables to get the natural width and height of the image.

const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);

const image = document.querySelector("#image");
useEffect(() => {
  if (image) {
    let linkSrc = image.src;
    const imageCopy = document.createElement("img");
    imageCopy.src = linkSrc;
    setWidth(imageCopy.width);
    setHeight(imageCopy.height);
  }
}, [width, height, image]);

I made a div element to put inside the img and svg elements so that the svg element would appear on the image. And I set the preserveAspectRatio to retain the x and y positions of rect and text elements when the screen size changes.

<div className="col-8">
  <div className="img-container">
    <img
      id="image"
      src="/img/foods.jpg"
      alt="food"
      className="w-100"
    />
    <svg
      preserveAspectRatio="none"
      className="image-map"
      viewBox={`0 0 ${width} ${height}`}
    >
      <rect className="selected-object"></rect>
      <rect className="wrap-text"></rect>
      <text className="object-name" x={xPosition} y={yPosition + 15}>
        {selectedItem}
      </text>
    </svg>
  </div>
</div>

css:

.img-container {
  position: relative;
}

.image-map {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

.selected-object {
  position: absolute;
  top: 0;
  left: 0;
  fill: transparent;
  stroke: #ff9e0d;
  stroke-width: 5px;
}

.wrap-text {
  fill: #ff9e0d;
}

.object-name {
  z-index: 999;
}

I started declaring the x,y,w,h variables and call these in svg’s rect and text elements.

const [xPosition, setXPosition] = useState(0);
const [yPosition, setYPosition] = useState(0);
const [objWidth, setObjWidth] = useState(0);
const [objHeight, setObjHeight] = useState(0);
const [selectedItem, setSelectedItem] = useState("");
<svg
  preserveAspectRatio="none"
  className="image-map"
  viewBox={`0 0 ${width} ${height}`}
>
  <rect
    className="selected-object"
    x={xPosition}
    y={yPosition}
    width={objWidth}
    height={objHeight}
  ></rect>
  <rect
    className="wrap-text"
    x={xPosition}
    y={yPosition}
    width={objWidth}
    height="20"
  ></rect>
  <text className="object-name" x={xPosition} y={yPosition + 15}>
    {selectedItem}
  </text>
</svg>

Then, I made a handleClick() to show the svg indicators on the image.

const handleClick = (object) => {
  objects.map((item) => {
    if (item.object === object) {
      setXPosition(item.x);
      setYPosition(item.y);
      setObjWidth(item.w);
      setObjHeight(item.h);
      setSelectedItem(object.toUpperCase());
    }
    return item;
  });
};

Called the function in this button:

<button
  className="btn btn-secondary col-12 my-2"
  key={item.object}
  onClick={() => handleClick(item.object)}
>
  {item.object}
</button>

And it’s done. You can run your simple app.

Comments (0)