Market Analysis With Computer Vision and IoT

by Apr 18, 2020Projects

Market Analysis with IoT is a python application that uses computer vision, Google cloud and graphing technologies to present raw sales data in a manner that is easy to comprehend for market analysts. This is a prototype that will help an FMCG company to analyse the movement of products from the retail stores in near real-time. It collects sales data, buyer’s age, origin and name of the product and stores it in Google cloud. This data is further represented in a visual dashboard that will be meaningful to the analysts. The application also provides an interface for the buyer to get useful product information.

Here is the schematic representation of the project. In this article we will delve deeper into the technical implementation of each of the blocks.

Contents

Computer Vision

Using OpenCV with Raspberry Pi for object detection

In this section, we learn about how to detect an object from an image or real-time video using Raspberry Pi and Python. Furthermore, we are using a Pi Camera to capture images and OpenCV to program the Image recognition.

1. Hardware Requirements

2. Initial Setup

You can follow the below tutorial to setup OpenCV to work on your windows system: https://iot4beginners.com/a-tutorial-on-opencv-python-with-raspberry-pi-for-image-recognition/

3. Pi Camera Installation

  1. Install the Raspberry Pi Camera module by inserting the cable into the Raspberry Pi. The cable fits into the slot situated between the Ethernet and HDMI ports, with the silver connectors facing the HDMI port as shown in the image below.
  1. Boot up your Raspberry Pi
  2. From the terminal, run “sudo raspi-config“. If the “camera” option is not listed, you have to run a few commands to update your Raspberry Pi. Run “sudo apt-get update” and “sudo apt-get upgrade
  3. Run “sudo raspi-config” again. You should now see the “camera” option.
  4. Navigate to the “camera” option, and enable it. Select “Finish” and reboot your Raspberry Pi.

4. Code Explanation

Read and Display frames using Pi Camera

  • Setup your pi camera as shown in the setup below
  • Firstly, we need to read and display the video input from the Pi Camera (Reference).
  • Since OpenCV works with images in BGR format we read the frames accordingly.
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))
# allow the camera to warmup
time.sleep(0.1)
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
	# grab the raw NumPy array representing the image
	image = frame.array
	# show the frame
	cv2.imshow("Frame", image)
	key = cv2.waitKey(1) & 0xFF
	# clear the stream in preparation for the next frame
	rawCapture.truncate(0)
	# if the `q` key was pressed, break from the loop
	if key == ord("q"):
		break

Find the HSV value range for the required colour/object. (colour_track.py)

  1. First, we read the camera input and display it continuously.
  2. Now adjust the sliders to get upper and lower values of Hue followed by Saturation, and finally Value(brightness). Once you get desired results, note down these values.
  3. For blue colour we adjust the track-bars as shown below: Similarly, you can adjust for other colours.
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
import numpy as np

import cv2
import numpy as np

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30
rawCapture = PiRGBArray(camera, size=(640, 480))
# allow the camera to warmup
time.sleep(0.1)

def nothing(x):
    pass

#trackbar initial Values
cv2.namedWindow("trackbar")
cv2.createTrackbar("L-H","trackbar",0,179,nothing)
cv2.createTrackbar("L-S","trackbar",0,255,nothing)
cv2.createTrackbar("L-V","trackbar",0,255,nothing)
cv2.createTrackbar("U-H","trackbar",179,179,nothing)
cv2.createTrackbar("U-S","trackbar",255,255,nothing)
cv2.createTrackbar("U-V","trackbar",255,255,nothing)

# capture frames from the camera
for image in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    # grab the raw NumPy array representing the image, then initialize the timestamp
    # and occupied/unoccupied text
    frame = image.array

    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)    
    # update these values in each iteration
    l_h=cv2.getTrackbarPos("L-H","trackbar")
    l_s=cv2.getTrackbarPos("L-S","trackbar")
    l_v=cv2.getTrackbarPos("L-V","trackbar")
    h_h=cv2.getTrackbarPos("U-H","trackbar")
    h_s=cv2.getTrackbarPos("U-S","trackbar")
    h_v=cv2.getTrackbarPos("U-V","trackbar")
    print(l_h,l_s,l_v,h_h,h_s,h_v)
    low=np.array([l_h,l_s,l_v])
    high=np.array([h_h,h_s,h_v])

    mask=cv2.inRange(hsv,low,high) # required part is stored as white(255),otherwise 0
    result=cv2.bitwise_and(frame,frame,mask=mask)

    cv2.imshow("result",result)
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)
    
    if cv2.waitKey(25)  & 0xFF==ord('q'):
           break

cv2.destroyAllWindows()

In the above code, Sliders are used to update upper and lower HSV values in each iteration and the same is used to display the result. (This part is explained further below in Step 2).

Read frames from Pi Camera and declare “GetValues” Function (Final_pi.py)

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
import numpy as np

In the Above lines, we import the necessary library.

  1. picamera to read frames from Raspberry Pi camera
  2. time to add time delay
  3. cv2 to detect colors in the current frame
  4. Numpy to generate range for HSV values
# initialize the camera and grab a reference to the raw camera capture
resx,resy=640,480
camera = PiCamera()
camera.resolution = (resx,resy)
camera.framerate = 40
rawCapture = PiRGBArray(camera, size=(resx,resy))
# allow the camera to warmup
time.sleep(0.1)

Here we initialize the camera (Frame Resolution and frame rate) and give a very small time delay for camera to warm up

#initialization Dictionary file
c_blue=c_red=c_green=c_orange=c_yellow=0
my_inventory= {'c_blue': 0, 'c_red': 0,'c_green': 0, 'c_orange': 0,'c_yellow': 0}

Now, we initialize a dictionary with the objects name as key (c_blue, c_red, c_yellow, etc).

#update these 2 values to change the range of size of the object being detected
area_low=resx*resy/100
area_high=20000

Next, we declare two variables to define the range of object area which is allowed. This helps to avoid any false detection and unwanted elements in the frame are ignored.

def GetValues(my_inventory):
    # capture frames from the camera
    for img in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
        # grab the raw NumPy array representing the image
        frame = img.array
        # convert frame from BGR format to HSV format
        hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
        font = cv2.FONT_HERSHEY_SIMPLEX

Here we read frame from pi camera and convert it to HSV from from BGR format, which is used to detect contours later on.

        #blue
        low_blue=np.array([88,128,136])
        high_blue=np.array([118,255,255])
        mask1=cv2.inRange(hsv,low_blue,high_blue)
        blur1=cv2.GaussianBlur(mask1,(15,15),0)
        contours1,_=cv2.findContours(blur1,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
        c_blue=0 #reset the values for count of blue object
        for contour1 in contours1:
            area1=cv2.contourArea(contour1)
            
            if (area1>area_low and area1<area_high):
                approx = cv2.approxPolyDP(contour1, 0.009 * cv2.arcLength(contour1, True), True) 
                n=approx.ravel()
                x=n[0]
                y=n[1]
                c_blue+=1
                cv2.drawContours(frame,[approx],0,(255,0,0),3)
                cv2.putText(frame,str(c_blue),(x,y), font, 2,(255,0,0),2,cv2.LINE_AA)
        cv2.putText(frame,'B='+str(c_blue),(50,50), font, 1,(255,0,0),2,cv2.LINE_AA)
        my_inventory["c_blue"]=c_blue

  • First, we declare low and high values for the blue color, which we got using the sliders as described previously.
  • Then, we create a  mask from the HSV frame using these range values.
  • Then we blur this a  little to filter out minor errors.
  • Finally, we detect all the contours for blue color and store it in contours1
  • Then, we start a loop and process each of the detected contours separately.
  • Based on the area of the contour we consider it if the area is within our required range,otherwise, we ignore it.
  • We increase “c_blue “ key-value by 1, draw an outline using drawContours, number it using putText
  • Finally, we update the my_inventory dictionary.

Similarly, we detect contours for other objects or colour just like we did for blue colour and update the dictionary.

    cv2.imshow("frame",frame) 
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)

Once all the processing part for the current frame is over, we display the modified frame

Next, we clear the rawCapture element to prepare for the next frame.

return cv2.waitKey(1)

Then, we return the cv2.waitKey(1) value. This value can be used in the part where the function is called from (shown below).

Call the GetValues function(Function_call.py)

import Final_pi #import the python file containing the function GetValues
import cv2
ls={}# to read the Dictionary file
val=0
while 1:
    val=Final_pi.GetValues(ls)#This function call updates the ls{} values
    print(ls)# print the dictionary
#Val hold the value read by cv2.waitKey(1). 27 is ASCII code for Esc key
    if val==27: 
        break;
cv2.destroyAllWindows() #destroy the window which displays frame 

The above part  is used to  call the GetValues function and update the dictionary which contains the object count.

Results

In the given example, only a single orange object is detected:

Output dictionaries

The program also displays a frame which shows the live stream of images along with the contours. (Press esc key to exit and stop the execution of the program)

Output frames

Cloud Integration

To share this data that we collected with the application we need to send this data to a cloud platform. For this project we will be using the Google Cloud Platform. Furthermore, In GCP we will be using the IoT core, Cloud Pub/Sub, Dataflow and BigQuery to accomplish our task.

Initial Setup

For the setup of things at the GCP dashboard you can follow steps from 2-9 in the following tutorial, it will take you through the entire process in a step by step manner:

Once you are done with these steps you can continue to follow this article.

Code Explanation

As far as the integration is concerned, there are only 2 functions that we have to make, one to send data and another to get data. Here we will have a look at both of these functions.

Send Data :

from google.cloud import pubsub_v1
from google.cloud import bigquery
import datetime
import json
import os
import time

The above snippet imports all the required libraries including “pubsub_v1” and “bigquery” which are responsible to send and receive data respectively.

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'YOUR-CREDENTIAL-FILE.json'

def send_data(data):
    project_id = "<project id >" # enter your project id here
    topic_name = "<Pub/Sub topic name >" # enter the name of the topic that you created

    publisher = pubsub_v1.PublisherClient()
    topic_path = publisher.topic_path(project_id, topic_name)

    futures = dict()

    def get_callback(f, data):
        def callback(f):
            try:
                # print(f.result())
                futures.pop(data)
            except:
                print("Please handle {} for {}.".format(f.exception(), data))

        return callback

    time.sleep(3)   
    print(data)
    # When you publish a message, the client returns a future.

    future = publisher.publish(
        topic_path, data=(json.dumps(data)).encode("utf-8")) # data must be a bytestring.

    # Publish failures shall be handled in the callback function.

    future.add_done_callback(get_callback(future, data))

    # Wait for all the publish futures to resolve before exiting.

    while futures:
        time.sleep(5)

    print("Published message with error handler.")
  • Line 1 declares an environment variable called ‘GOOGLE_APPLICATION_CREDENTIALS’ whose value has been set to the path to the credentials json file that you downloaded from GCP.
  • Next, we declare a function called ‘send_data‘ which takes in a dictionary as a parameter. this is what will be sent to the Pub/Sub topic as a message.
  • NOTE – the keys of this dictionary must match with the field names in your BigQuery table.
  • In lines 7-8 we create an instance of the “PublisherClient” and create the path to the topic.
  • In line 26 we convert the dictionary to a json object, convert it to a bytestring and publish the message to the specified topic

Get data

Next we need to write the function to get data from the BigQuery table, here is the function:

def get_data():
    client = bigquery.Client()
    QUERY = (
    'SELECT * FROM `YOUR-TABLE` LIMIT 1000')
    query_job = client.query(QUERY)  # API request
    rows = query_job.result()  # Waits for query to finish
    rows = list(rows)
    for i in range(len(rows)) :
        rows[i] = list(rows[i])
        rows[i][0] = rows[i][0].strftime("%m/%d/%Y, %H:%M:%S")
        
    return rows
  • In line 2 we create an instance of the BigQuery client and call it ‘client’
  • Next, we write the query and store it in a variable called “QUERY”
  • In line 5 we make an API request and query the table.
  • The result of the query is stored in a variable called “rows“.
  • In line 9 we convert the data that we get from BigQuery into a python list
  • In line 10 we convert the datetime object into a string to use as a label in a graph later.

Graphing Analysis (graphing.py)

Structured data is obtained from BigQuery (Google Cloud Platform) which is stored as a two dimensional list.

The data returned by “get_data” is of the format :

[['Date and time', 'product name' , 'age of  customer' , 'Origin', { product stacking info}]]

Here is some sample data:

data= [['04/10/2020, 18:00:39', 'mango', 56, 'farm', "{'orange': 0, 'yellow': 0, 'green': 0, 'red': 0, 'blue': 0}"], ['04/12/2020, 06:34:27', 'banana', 63, 'farm>dealer>supermarket', "{'red': 0, 'yellow': 3, 'green': 2, 'blue': 1, 'orange': 0}"],['04/10/2020, 8:00:39', 'mango', 63, 'farm', "{'orange': 0, 'yellow': 1, 'green': 5, 'red': 0, 'blue': 4}"],['05/10/2020, 13:00:39', 'mango', 33, 'farm', "{'orange': 3, 'yellow': 0, 'green': 4, 'red': 0, 'blue': 0}"]]

Python Modules Used

import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from pandas.plotting import register_matplotlib_converters

We use Pandas and matplotlib for data manipulation and plotting operation. While datetime is used to deal with datetime data.

Function Description

def get_plot(data):
    
    print(data)
    
    age_list=[]
    blue = []
    green = []
    yellow =[]
    orange = []
    num_per_age = [0 for i in range(10)]  #To divide age into 10 equal points.
    timestamp_list = []

get_plot function takes data list as an argument. We manipulate data obtained as an argument to the function and  store it in the lists shown above.

    for row in data:
        if (row[2]>0 and row[2]<=10):
            num_per_age[0]+=1
        elif(row[2]>10 and row[2]<=20:
            num_per_age[1]+=1
        elif(row[2]>20 and row[2]<=30):
            num_per_age[2]+=1
        elif(row[2]>30 and row[2]<=40):
            num_per_age[3]+=1
        elif(row[2]>40 and row[2]<=50):
            num_per_age[4]+=1
        elif(row[2]>50 and row[2]<=60):
            num_per_age[5]+=1
        elif(row[2]>60 and row[2]<=70):
            num_per_age[6]+=1
        elif(row[2]>70 and row[2]<=80):
            num_per_age[7]+=1
        elif(row[2]>80 and row[2]<=90):
            num_per_age[8]+=1
        else:
            num_per_age[9]+=1

The age is received in the form of integers. We must convert those ages into a string which signifies the range of age to which the customer belongs. To achieve this we must keep a count on the range of age category. We do this with a set of ifelifelse statements.

    for i in range(0,100,10):
        age_list.append(str(i)+"to"+str(i+10))

Here we loop through numbers from 0 to 100 by skipping 10 numbers in between to create the age_list, which contains the category of ages.

To plot age distribution graph :

    series = pd.Series(num_per_age,index=age_list, name='age distribution')
    series.plot.pie(figsize=(6, 6))
    plt.show()

The pie chart shows the range of ages of the people who visit the market. From the above graph we infer that the age range of 60 to 70 visits the market more.

To plot the count of items in the shelf :

for row in data: #this takes the count of blue,green,yellow,orange
        blue.append(eval(row[4])["blue"])
        blue_sum = sum(blue)        
        green.append(eval(row[4])["green"])
        green_sum = sum(green)
        yellow.append(eval(row[4])["yellow"])
        yellow_sum = sum(yellow)
        orange.append(eval(row[4])["orange"])
        orange_sum = sum(orange)       
    df=pd.DataFrame({'blue': [blue_sum],'green': [green_sum],'yellow' [yellow_sum],'orange': [orange_sum]})
    df.plot(kind='bar',color=['b','g','r','y'])
    plt.show()

Pandas DataFrame is two-dimensional size-mutable, potentially heterogeneous tabular data structure with labeled axes (rows and columns). In the real world, a Pandas DataFrame will be created by loading the datasets from existing storage.

This bar graph shows the stacking up of the products (unsold products). We can see that the green bar is the tallest among the four, hence we may infer that green is the least sold product.

To plot time-series graph:

register_matplotlib_converters()
    for row in data:
        timestamp_list.append(datetime.strptime(row[0],"%m/%d/%Y, %H:%M:%S"))
        df = pd.DataFrame({'timestamp_list': timestamp_list,'blue': blue,'green': green,'yellow': yellow,'orange': orange})

    fig, axs = plt.subplots(2, 2)
    plt.figure(figsize=(7,7))
    
    df.plot(kind='line',x='timestamp_list',y='blue',color="blue",ax=axs[0,0])
    df.plot(kind='line',x='timestamp_list',y='green',color="green",ax=axs[0,1])
    df.plot(kind='line',x='timestamp_list',y='yellow',color="yellow",ax=axs[1,0])
    df.plot(kind='line',x='timestamp_list',y='orange',color="orange",ax=axs[1,1])

    plt.show()

This figure is a set of 4 subplots of the stock of a product with respect to time. In this case, greater the negativity of the slope greater the sales of a product . Which means that the given graph represents the stock of the product rather than the sales. The slope of the Blue and yellow objects are negative, which means they are getting sold at a faster rate. Similarly, green and orange products are stacking up.

With this we have plotted all the data from BigQuery in a manner easy to understand for everyone.

Graphical User Interface (gui.py)

In this project, we have used Tkinter to program a desktop GUI. Tkinter is Python’s de-facto standard GUI (Graphical User Interface) package. It is a simple library that helps you create windows, buttons, Entry boxes and many more widgets. In this project, there are four different windows :

  • Welcome page
  • Analytics page
  • Product Info page
  • Product info entry

Initial Code Setup

Before we begin creating our GUI, we have to import a few packages as well as the other scripts that we had written earlier.

from tkinter import *
from tkinter.ttk import *
import tkinter.font as tkFont
import time
from cv.detect_colours import detect_colour
from sendmsg import send_data
from sendmsg import get_data
from graphing import get_plot
import cv.bought as bought
  • The lines 1-4 import all the packages that are required majorly for the GUI as well as the time module to deal with time data.
  • The rest of the lines import other python scripts that have been explained in detail earlier.

To create the app we will be creating a class and specifying each page and button commands as methods of that class.

class app():
    def __init__(self, root):
        self.root = root
        self.height = self.root.winfo_screenheight() 
        self.width = self.root.winfo_screenwidth()
        self.app_width = int(0.5*self.width)
        self.app_length = int(0.5*self.height)
        self.root.geometry(str(self.app_width)+"x"+str(self.app_length))
        self.root.title("Market Analysis")
        self.colour_count = {}
        self.create()
  • In the above snippet we are creating a class named app and defining the __init__ method, which has a parameter as the root window.
  • using “self.root.winfo_screenheight()” and “self.root.winfo_screenwidth()” we get the height and width of the screen. We use this in order to make the app’s size relative to the size of the user’s screen.
  • After this we set the app’s dimension and title as well and initialize the colour_count variable which will be accessible to many methods.
  • finally we call the create method This is what launches the welcome page of the app.

Welcome Page

The welcome page has a very simple design. It contains the text “Welcome to the market analysis app” as a Tkinter label. It also has a menu bar on the top that allows you to navigate to the other 2 important pages, namely the Analytics page and the Product Info page. Here is a sample screenshot

Now lets go through the code snippet of the page.

    def create(self):
        menubar = Menu(self.root)  
        menubar.add_command(label="Analytics", command=self.Analytics_page)
        menubar.add_command(label="Product info", command=self.customer_page)  
        self.root.config(menu=menubar)
        welcome_font = tkFont.Font(family="Lucida Grande", size=55)
        welcome_label = Label(self.root, text='Welcome To\nThe Market Analysis App ',font=welcome_font)
        welcome_label.pack(fill='both', expand=True, anchor=CENTER)

  • Lines 1-4 create the menu bar present on top of the screen, these are the buttons that lead you to the pages having the various purposes. The commands that they have been given are the methods that open the respective pages.
  • Then, in lines 6-9 we create the welcome text to be displayed on the window.

Analytics Page

The analytics page is where we have the option to start the camera functionality as well as to generate the graphs from data pulled from BigQuery. This is the part of the application that is used by the FMCG companies.

Now lets go through the code :

    def Analytics_page(self):
        
        analytics_page = Tk()
        analytics_page.geometry(str(int(0.5*self.width))+"x"+str(int(0.5*self.height)))
        analytics_page.title("Analytcis Page")

        canvas = Canvas(analytics_page)
        canvas.create_line(0, 0.20*self.app_length, self.app_width, 0.20*self.app_length)  
        canvas.pack(fill = BOTH, expand = True)
        
        a = Button(analytics_page,text="Start Shelf Cam", command=lambda: detect_colour(self.product_info_entry, self.colour_count))
        a.place(relx=0.5, rely=0.25, anchor=CENTER)
        
        button_desc_a = Label(analytics_page, text="Select this button to begin looking for specified objects on the shelf")
        button_desc_a.place(relx=0.5, rely=0.355, anchor=CENTER)

        canvas.create_line(0, 0.375*self.app_length, self.app_width, 0.375*self.app_length)  
        canvas.pack(fill = BOTH, expand = True)
        
        b = Button(analytics_page,text="Get Graphs", command= lambda: get_plot(get_data()))
        b.place(relx=0.5, rely=0.425, anchor=CENTER)

        button_desc_b = Label(analytics_page, text="Select this button to get a plot of the current sales of the objects in the shelf.")
        button_desc_b.place(relx=0.5, rely=0.520, anchor=CENTER)

        canvas.create_line(0, 0.540*self.app_length, self.app_width, 0.540*self.app_length)  
        canvas.pack(fill = BOTH, expand = True)

        analytics_page.mainloop()
  • Lines 3-5 initialize the analytics page
  • In the lines 7-9, 17-18 & 26-27 we create a Tkinter canvas so that we can draw the horizontal lines that you see in the app. This is mainly to make the app look more organized.
  • Lines 11-12 and 20-21 create and place the two buttons found on this page. These buttons initiate the functions such as “detect_colour” and “get_plot”.

Product Info Page

This page helps the customer display any information that may be relevant to them. In this case we display the origin of the product.

Lets have a look at the code :

    def customer_page(self):
        customer_page = Tk()
        customer_page.geometry(str(int(0.5*self.width))+"x"+str(int(0.5*self.height)))
        customer_page.title("Product Info Page")

        box_desc = Label(customer_page, text="Product Name :")
        box_desc.place(relx=0.5, rely=0.205, anchor=CENTER)

        product_name = Entry(customer_page)
        product_name.place(relx=0.5, rely=0.25, anchor=CENTER)

        self.disp_info = Text(customer_page, height=int(0.5*self.app_length), width=self.app_width, font=("Helvetica", 32))
        self.disp_info.place(relx=0,rely=0.5)

        submit_button = Button(customer_page, text="Submit", command=lambda:(self.Sub_func(product_name.get())))
        submit_button.place(relx=0.5, rely=0.320, anchor=CENTER)

        customer_page.mainloop()

    def Sub_func(self, name):
        self.disp_info.configure(state="normal")
        self.disp_info.delete('1.0', END)
        self.data = get_data()
        for i in self.data:
            if i[1] == name:
                self.disp_info.insert(END,"Name : "+i[1]+"\n")
                self.disp_info.insert(END,"Origin : "+i[3]+"\n")
        self.disp_info.configure(state="disabled")

  • In lines 9-10 we create a text entry widget where the customer types in the object name.
  • Lines 12-13 initialize and place the text widget. This is where the required data is displayed.
  • The submit function “Sub_func” is what runs when you click submit. It takes the entered string as an argument “product_name.get()“.
  • The “Sub_func” configures the “Text” widget to be normal which means entry is allowed and also deletes any information that is already present in the widget.
  • It then gets data from the BigQuery table and looks for an object whose name matches with the one entered by the user.
  • Then it inserts the required data into the “Text” widget.
  • Finally it disables any further entry to prevent tampering of the data by the user.

Product Info Entry

But how does the information displayed above get generated ? A simple solution to this issue is to take user input. This is the function of the product info page. This window pops up whenever it detects a change in the number of objects present on the shelf. here is a sample :

Here is the code:

    def product_info_entry(self):

        def false_alarm ():
            product_entry.destroy()
            detect_colour(self.product_info_entry, self.colour_count)

        def submit_json ():
            object_desc = {}
            object_desc["name"] = e1.get()
            object_desc["age"] = int(e2.get())
            object_desc["origin"] = e3.get()
            object_desc["sales"] = str(self.colour_count)
            object_desc["timestamp"] = time.time()
            object_desc["bought"] = str(bought.bought)
            print(object_desc)
            send_data(object_desc)
            
            product_entry.destroy()
            detect_colour(self.product_info_entry, self.colour_count)
            
            
        product_entry = Tk()
        product_entry.geometry(str(int(0.3*self.width))+"x"+str(int(0.3*self.height)))
        product_entry.title("Product Info Page")

        Label(product_entry, text="Product Name").place(relx=0.2, rely=0.2)
        Label(product_entry, text=" Age").place(relx=0.2,rely=0.3)
        Label(product_entry, text=" Origin").place(relx=0.2,rely=0.4)

        e1 = Entry(product_entry)
        e2 = Entry(product_entry)
        e3 = Entry(product_entry)

        e1.place(relx=0.5, rely=0.2)
        e2.place(relx=0.5,rely=0.3)
        e3.place(relx=0.5,rely=0.4)

        Sub = Button(product_entry, text="Submit", command=submit_json)
        Sub.place(relx=0.5,rely=0.7)

        fp = Button(product_entry, text="False Positive", command=false_alarm)
        fp.place(relx=0.5,rely=0.8)
        
        product_entry.mainloop()

  • In lines 3-5 we define a function called “false_alarm” . This function has to be activated when an object has been detected by mistake. This function kills the product info window and restarts the colour detection function.
  • In lines 7-19 we define the function “submit_json” which converts all the collected data into a dictionary such that it can fit into the BigQuery table. Finally it uses the “send_data” function to send the dictionary to BigQuery.
  • In lines 22-42 we create 3 different Entry widgets to get data such as the product’s name, age of the buyer and the origin of the product.

Running the App

This is the part of the app where it actually runs all the code.

if __name__ == "__main__": 

    root = Tk()
    analysis_app = app(root)
    root.mainloop()
  • Here we initialize the main window with Tk().
  • Finally, we will create a new instance of the app called “analysis_app” and pass “root” as a parameter and call the “mainloop” method.

With this we conclude the basic tutorial on how we can use Computer vision, Google Cloud, Matplotlib, Tkinter and a few other software to create a useful application such as the one we just built.

For the entire directory of code used in this project you can visit the GitHub repository here:
https://github.com/sashreek1/Market-Analysis-Tool

We hope you all learnt something new from this tutorial, Happy Learning 🙂

Creating a multiplication Skill in Alexa using python

Written By Sashreek Shankar

Hey reader! I am Sashreek, a 16 year old programmer who loves Robotics, IoT and Open Source. I am extremely enthusiastic about the Raspberry Pi and Arduino hardware as well. I also believe in sharing any knowledge I have so feel free to ask me anything 🙂

RELATED POSTS

How to Simulate IoT projects using Cisco Packet Tracer

How to Simulate IoT projects using Cisco Packet Tracer

In this tutorial, let's learn how to simulate the IoT project using the Cisco packet tracer. As an example, we shall build a simple Home Automation project to control and monitor devices. Introduction Firstly, let's quickly look at the overview of the software. Packet...

How to design a Wireless Blind Stick using  nRF24L01 Module?

How to design a Wireless Blind Stick using nRF24L01 Module?

Introduction Let's learn to design a low-cost wireless blind stick using the nRF24L01 transceiver module. So the complete project is divided into the transmitter part and receiver part. Thus, the Transmitter part consists of an Arduino Nano microcontroller, ultrasonic...

How to implement Machine Learning on IoT based Data?

How to implement Machine Learning on IoT based Data?

Introduction The industrial scope for the convergence of the Internet of Things(IoT) and Machine learning(ML) is wide and informative. IoT renders an enormous amount of data from various sensors. On the other hand, ML opens up insight hidden in the acquired data....

Smart Display Board based on IoT and Google Firebase

Smart Display Board based on IoT and Google Firebase

Introduction In this tutorial, we are going to build a Smart Display Board based on IoT and Google Firebase by using NodeMCU8266 (or you can even use NodeMCU32) and LCD. Generally, in shops, hotels, offices, railway stations, notice/ display boards are used. They are...

Smart Gardening System – GO GREEN Project

Smart Gardening System – GO GREEN Project

Automation of farm activities can transform agricultural domain from being manual into a dynamic field to yield higher production with less human intervention. The project Green is developed to manage farms using modern information and communication technologies....

How to build a Safety Monitoring System for COVID-19

How to build a Safety Monitoring System for COVID-19

It is expected that the world will need to battle the COVID-19 pandemic with precautious measures until an effective vaccine is developed. This project proposes a real-time safety monitoring system for COVID-19. The proposed system would employ an Internet of Things...

VIDEOS – FOLLOW US ON YOUTUBE

EXPLORE OUR IOT PROJECTS

IoT Smart Gardening System – ESP8266, MQTT, Adafruit IO

Gardening is always a very calming pastime. However, our gardens' plants may not always receive the care they require due to our active lifestyles. What if we could remotely keep an eye on their health and provide them with the attention they require? In this article,...

How to Simulate IoT projects using Cisco Packet Tracer

In this tutorial, let's learn how to simulate the IoT project using the Cisco packet tracer. As an example, we shall build a simple Home Automation project to control and monitor devices. Introduction Firstly, let's quickly look at the overview of the software. Packet...

All you need to know about integrating NodeMCU with Ubidots over MQTT

In this tutorial, let's discuss Integrating NodeMCU and Ubidots IoT platform. As an illustration, we shall interface the DHT11 sensor to monitor temperature and Humidity. Additionally, an led bulb is controlled using the dashboard. Besides, the implementation will be...

All you need to know about integrating NodeMCU with Ubidots over Https

In this tutorial, let's discuss Integrating NodeMCU and Ubidots IoT platform. As an illustration, we shall interface the DHT11 sensor to monitor temperature and Humidity. Additionally, an led bulb is controlled using the dashboard. Besides, the implementation will be...

How to design a Wireless Blind Stick using nRF24L01 Module?

Introduction Let's learn to design a low-cost wireless blind stick using the nRF24L01 transceiver module. So the complete project is divided into the transmitter part and receiver part. Thus, the Transmitter part consists of an Arduino Nano microcontroller, ultrasonic...

Sending Temperature data to ThingSpeak Cloud and Visualize

In this article, we are going to learn “How to send temperature data to ThingSpeak Cloud?”. We can then visualize the temperature data uploaded to ThingSpeak Cloud anywhere in the world. But "What is ThingSpeak?” ThingSpeak is an open-source IoT platform that allows...

Amaze your friend with latest tricks of Raspberry Pi and Firebase

Introduction to our Raspberry Pi and Firebase trick Let me introduce you to the latest trick of Raspberry Pi and Firebase we'll be using to fool them. It begins with a small circuit to connect a temperature sensor and an Infrared sensor with Raspberry Pi. The circuit...

How to implement Machine Learning on IoT based Data?

Introduction The industrial scope for the convergence of the Internet of Things(IoT) and Machine learning(ML) is wide and informative. IoT renders an enormous amount of data from various sensors. On the other hand, ML opens up insight hidden in the acquired data....

Smart Display Board based on IoT and Google Firebase

Introduction In this tutorial, we are going to build a Smart Display Board based on IoT and Google Firebase by using NodeMCU8266 (or you can even use NodeMCU32) and LCD. Generally, in shops, hotels, offices, railway stations, notice/ display boards are used. They are...

Smart Gardening System – GO GREEN Project

Automation of farm activities can transform agricultural domain from being manual into a dynamic field to yield higher production with less human intervention. The project Green is developed to manage farms using modern information and communication technologies....