How to Create a Simple Object Detector with NextJs

Written by guesthu | Published 2021/11/06
Tech Story Tags: nextjs | reactjs | javascript-tutorial | tutorial | javascript | simple-object-detector | programming | react

TLDRThe function of this simple app is to indicate the object’s location in the image whenever the user clicks any of the labeled buttons. It shows the object's location in an image whenever a user clicks a button. The app was created with NextJs.via the TL;DR App

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

To begin with, first, I created a simple design layout. (Bootstrap 5 was installed).

const ImageDetector = () =>{
 return(
    <>
        <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="photo"
                    className="w-100"
                    />
                </div>
            </div>
        </div>
    </>
 )
}
export default ImageDetector;

I declared a variable containing an array of objects.

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
        },
    ];

After declaration, I fetched the values from that variable, objects, and converted them into 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, I declared width and height variables to get the natural width and height of the image.

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

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

Then, I inserted <svg/> below the <img/> and put them inside a <div/> then made its position relative. I defined the css style of the <svg/> to overlay the <img/>. The preserveAspectRatio and viewBox in <svg/> will help retain the x and y positions of rect and text elements even when the screen size changes.

<div className="col-8">
    <div style={{"position":"relative"}}>
        <img
        id="image" 
        src={`/img/foods.jpg`} 
        alt="photo"
        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"> </text>
        </svg>
    </div>
</div>

<style jsx>
    {`
        .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;
        }
    `}
</style>

I inserted variables to set values of the x,y,w,h 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("");

Created handleClick() so when the user clicks a button the rect svg will appear.

const handleClick = ( object:string ) =>{
    objects.map(item =>{
        if(item.object === object){
            setXPosition(item.x);
            setYPosition(item.y);
            setObjWidth(item.w);
            setObjHeight(item.h);
            setSelectedItem(object.toUpperCase());
        }
    });
}
<div className="col-4">
    {objects.map(item=>(
        <button 
        className={"btn btn-secondary col-12 my-2"} 
        key={item.object}
        onClick={() => handleClick(item.object)} 
        >
        {item.object}
        </button>
    ))}
</div>

Then I set the values of rect and text elements and edited my style css.

<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>

<style jsx>
    {`
        .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;
        }
    `}
</style>

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


Written by guesthu | A web developer who loves writing and painting.
Published by HackerNoon on 2021/11/06