OSU-AIMS / tic-tac-toe

Vision based pick and place project with human versus robot game.
Apache License 2.0
3 stars 1 forks source link

RGB Image Kernel-Based Board Pose Detection #10

Closed MohammadKhan-3 closed 2 years ago

MohammadKhan-3 commented 2 years ago

Goal:

Create an Image Kernel to pass over a frame from Intel Realse d435i camera to detect a blue, red, and green square.

Computer Environment:

Current State:

Issue:

Screenshot from 2021-11-01 15-39-47

Code:

## IMPORTS
import sys
import os

# Add game_scripts directory to the python-modules path options to allow importing other python scripts
# insert at 1, 0 is the script path (or '' in REPL)
# sys.path.insert(1, '//home/martinez737/tic-tac-toe_ws/src/tic_tac_toe/game_scripts')
ttt_pkg = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
path_2_game_scripts = ttt_pkg + '/game_scripts'
sys.path.insert(1, path_2_game_scripts)

import rospy
import tf2_ros
import cv2

# ROS Data Types
from sensor_msgs.msg import Image
from geometry_msgs.msg import TransformStamped

# Custom Tools
    # from Realsense_tools import *
from transformations import *
from shape_detector import *
from cv_bridge import CvBridge, CvBridgeError

# System Tools
import pyrealsense2 as rs
import time
from math import pi, radians, sqrt, atan
import numpy as np
import matplotlib.pyplot as plt 

def kernel_color_detect(image):
    '''
    purpose: slides an array (nxn pixels) across an image to find color
    - obtain heat map of the color
    - find pixel location
    - get transform
    '''     
    # Uncomment below when using camera feed
    frame = image.copy()
    # cv2.imshow('Frame',frame)
    # cv2.waitKey(0)

    # rows = len(frame)
    # cols = len(frame[0])
    # print(rows) # 480
    # print(cols) # 640

    # Uncomment below when using image
    # test_image= os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/sample_content/sample_images/CorrectedColoredSquares_Color.png'
    # frame = cv2.imread(test_image)

    # Uncomment for Debuggging Frame
    # print(frame)
    # size = frame.shape
    # print(size)

    # make matrix size 50x50 with rgb values inside
    # red = [255,0,0]
    # green = [0,255,0]
    # blue = [0,0,255]

    # Ref: https://www.geeksforgeeks.org/image-filtering-using-convolution-in-opencv/amp/
    # Plan as of 10/20/21: use read image into kernel matrix then perform convolutions 
    # GeeksforGeeks use Python 3 (we have Python 2.7)

    # Obtain directory for blue, green, red square crops
    blue_square_crop = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/sample_content/sample_images/blue_square_crop.png'
    green_square_crop = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/sample_content/sample_images/green_square_crop.png'
    red_square_crop = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/sample_content/sample_images/red_square_crop.png'

    # Numpy: uses (y,x) / OpenCv (x,y)
    blue_square = cv2.imread(blue_square_crop)

    # Uncomment: Checking to see if original frame being read is flipped
    # cv2.imshow('Blue Square',blue_square)
    # cv2.waitKey(0)

    kernel_blue = np.zeros((51,51))  # creating an empty array
    # Uncomment below to use RGB values as kernel
    kernel_blue = np.append(kernel_blue,[0,0,255])

    # Uncomment below to use image as kernel
    # kernel_blue = np.append(kernel_blue,blue_square)
    # print('kernel_blue:',kernel_blue)
    # kernel_blue = np.asanyarray(kernel_blue,np.float32)

    # kernel_blue = cv2.flip(kernel_blue,-5)
    # can't assume kernel to be symmetric matrix, need to flip it before passing it to filter2D
    # cv2.flip()
    # negative number: flips about both axes
    #  0: flip around x-axis
    # positive number: flip around y-axis
    # docs on cv2.flip: https://docs.opencv.org/4.5.3/d2/de8/group__core__array.html#gaca7be533e3dac7feb70fc60635adf441

    # Uncomment below for debugging
    # print('Kernel')
    # print(kernel_blue) # Also not finding the Kernel
    # Kernel size must by n x n where n- odd numbers
    # blue, green, and red square crops are 55 x 55 pixels
    blue_heatmap = cv2.filter2D(frame,-3,kernel_blue)
    blue_heatmap = cv2.applyColorMap(blue_heatmap,cv2.COLORMAP_HOT)
    # cv2.applyColorMap() changes color of heatmap

    print('Blue HeatMap: ',blue_heatmap)
    # opencv docs on filter2D:
    # https://docs.opencv.org/4.2.0/d4/d86/group__imgproc__filter.html#ga27c049795ce870216ddfb366086b5a04
    '''
    filter2D parameters:
        InputArray src, 
        OutputArray dst, 
        int ddepth, 
        InputArray kernel,
        Point anchor = Point(-1,-1),
        double delta = 0,
        int borderType = BORDER_DEFAULT   
    '''
    plt.figure(1) # Realsense Frame
    plt.imshow(cv2.cvtColor(frame,cv2.COLOR_BGR2RGB))
    plt.figure(2) # HeatMap Output
    plt.imshow(cv2.cvtColor(blue_heatmap,cv2.COLOR_BGR2RGB))
    plt.show()`
MohammadKhan-3 commented 2 years ago

Flip it about about both horizontal axis to try to get the shape in the correct orientation.

The correct orientation is below the x-axis. Screenshot from 2021-11-01 15-59-59

Reason for Flipping Kernel:

Next Step:

MohammadKhan-3 commented 2 years ago

Tried resizing the image after the convolution to back to its original size which resulted in the heat map in the correct location but still flipped about the x-axis.

Screenshot from 2021-11-03 16-35-40

I then tried the cv2.flip() function about both the x & y axis which pushes the heat map to the correct location.

Screenshot from 2021-11-03 16-31-17

Next Steps:

MohammadKhan-3 commented 2 years ago

Changes:

Changed kernel to 5x5

Potential Reason for Previous errors:

Next Steps:

MohammadKhan-3 commented 2 years ago

Contour Detection of heatmap

Screenshot from 2021-11-08 15-15-23

Screenshot from 2021-11-08 15-15-23(1)

Obtain pixel locations of blue region

Plan of Action: (In progress as of 11/8) - Find centers of contours Current Error: ~~`raise Exception(("Contours tuple must have length 2 or 3, " Exception: Contours tuple must have length 2 or 3, otherwise OpenCV changed their cv2.findContours return signature yet again. Refer to Open CV's documentation in that case'~~ - need a way to filter out other blue, red, green detected from the actual square

Rechecking Heat Map: 11/9

MohammadKhan-3 commented 2 years ago

Rechecking HeatMap

Screenshot from 2021-11-09 14-04-06

MohammadKhan-3 commented 2 years ago

Rechecking Heatmap

Next Steps:

acbuynak commented 2 years ago

Found the first issue. I think the kernel was being assembled incorrectly.

Original errored kernel creation

kernel_size = 25
kernel_blue = np.zeros((kernel_size,kernel_size))  # creating an empty array
kernel_blue = np.append(kernel_blue,[0,0,255])
kernel_blue = np.asanyarray(kernel_blue,np.float32)

This creates a float32 array of shape {628,1} containing values of either 0 or 255. Not the desired kernel.

Suggested correction: Note, I'm using uint8 data type to agree with the imported image.

# Create kernel (format - "BGR")
kernel_size  = 5
kernel_b     = 255 * np.ones((kernel_size, kernel_size, 1), dtype='uint8')
kernel_gr    = np.zeros((kernel_size, kernel_size, 2), dtype='uint8')
kernel       = np.dstack((kernel_b,kernel_gr))

Still working on the cv2.filter2D image parsing.

acbuynak commented 2 years ago

Taking some notes here from experimenting with cv2.filter2D

Test Image

Shape: 400x400 pixel. 8-bit. RGB Image Stack Grayscale Slices ( R - G - B )
image image


Setup

The cv2.filter2D filter accepts depth arrays, but the source and kernel frames must depth (as expected). Thus, an m x n x d source image must have a kernel of equal depth o x p x d.

Using ImageJ / Fiji to inspect produced images.


Effects of Kernel Size

Kernel sizes tested as ratio of image coverage. ex: 50x50 px kernel on 400x400 px image is (2500/160000)=1.56% coverage Documentation on pixel size (link)

The function uses the DFT-based algorithm in case of sufficiently large kernels (~11 x 11 or larger) and the direct algorithm for small kernels.

Settings: ddepth=-1 1.56% = 50x50 0.39% = 25x25 0.14% = 15x15 0.09% = 12x12
50 25 15 12


Effects of ddepth Setting

Documentation Link Kernel Size = 15x15 -1
(Match Source Depth)
0 1 2 3
-1 0 1 2 3
image image image x x
acbuynak commented 2 years ago

Alternative Technique using cv2.matchTemplate

Method Options

Documentation Link Kernel Size: 15 x 15 px Usage:

image = cv2.imread("test_image_RGB.tiff")
image = image[:, :, 0]    # cv2 uses BGR format. Thus, blue is channel 0
kernel_size = 15
kernel = 255 * np.ones((kernel_size, kernel_size), dtype='uint8')
res = cv2.matchTemplate(image=image, templ=kernel, method=0)
Option Filter Result Option Filter Result
0 image 1 image
2 image 3 image
4 image 5 image
acbuynak commented 2 years ago

Out of curiosity and the potential for progress using cv2.matchTemplate, I plugged a sample image into each method of the filter to obtain the below results.

Test Image

Original Image is RGB Size: 640 x 360 px

Only the BLUE channel is passed into the below filter. image

Testing

image = cv2.imread("sample_image.png")
image = image[:, :, 0]    # cv2 uses BGR format. Thus blue is channel 0
kernel_size = 15
kernel = 255 * np.ones((kernel_size, kernel_size), dtype='uint8')
res = cv2.matchTemplate(image=image, templ=kernel, method=0)
Option Filter Result Option Filter Result
0 image 1 image
2 image 3 image
4 image 5 Did not capture

!! Important: Results from Methods 0 and 2 are misleading as to the magnitude of each cell's values. Their grayscale brightness is scaled by ImageJ for readability, but their real value is in the range of 10^-7 or approx zero.

acbuynak commented 2 years ago

In regards to cv2.matchTemplate, method 1 seems to produce the most useful results with a clear gradient across color regions of interest.

MohammadKhan-3 commented 2 years ago

Next Steps:

If the above works continue to large image sizes

acbuynak commented 2 years ago

Added convolution testing sample images and test script @ 46aec0aae91f4c821586a45990c2ef51da2f3087

MohammadKhan-3 commented 2 years ago

Created 10x10 px image & ran 3x3 kernel using Filter2D

Input Image: (originally .tiff file but GitHub doesn't support it) input image

Output Image Array from filter2D: (originally .tiff file but GitHub doesn't support it) dst_image

I used Scott Lab computers for this and was not able to check pixel values to see if a gradient was created. Below is the code to create a kernel with 3 channels

Kernel Creation

# Create kernel (format - "BGR")  
kernel_size = 3
kernel = np.dstack((255 * np.ones((kernel_size, kernel_size, 1), dtype='uint8'),np.zeros((kernel_size, kernel_size, 3), dtype='uint8'))) # format: BGR
 # numpy dstack docs: https://numpy.org/doc/stable/reference/generated/numpy.dstack.html
 kernel_b = 255 * np.ones((kernel_size, kernel_size), dtype='uint8')

Filter2D method:

dst = image.copy()
output = cv2.filter2D(src=image, dst=dst, ddepth=-1, kernel=kernel_b)
cv2.imshow('Heatmap',output)
cv2.imshow('Output Array dst', dst)
cv2.imwrite("dst.tiff", dst)
cv2.imwrite("result.tff", output)

Next Steps:

MohammadKhan-3 commented 2 years ago

MatchTemplate Function

Notes on how function works:

Screenshot from 2021-11-18 14-16-48(1)

 # # Method: Template Matching
image = image[:, :, 0]
# img_gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# resb = cv2.matchTemplate(image=image[:, :, 0], templ=kernel_b, method=1)
# resg = cv2.matchTemplate(image=image[:, :, 1], templ=kernel_b, method=1)
# resr = cv2.matchTemplate(image=image[:, :, 2], templ=kernel_b, method=1)
# cv2.imwrite('resb.tiff',resb)
# cv2.imwrite('resg.tiff',resg)
# cv2.imwrite('resr.tiff',resr)
# template = kernel_b[1,:,:]

res = cv2.matchTemplate(image=image,templ=kernel_b,method=1)
cv2.imwrite('res.tiff',res)

Drew a bounding box on where the function thinks the square is: Screenshot from 2021-11-18 14-34-37

Next Steps:

MohammadKhan-3 commented 2 years ago

Checking Filter2D():

MohammadKhan-3 commented 2 years ago

Checking MatchTemplate():

Detecting Box

MatchTemplate_OUTPUT

Detecting Split

MatchTemplate_SPLIT_OUTPUT

Detecting Angle color

MatchTemplate_ANGLE_OUTPUT


Conclusion:

As expected, the MatchTemplate is sensitive to subtle changes of the object. It works well if the object is in the same orientation and size but if it isn't, the detection breaks down quickly.

Code for MatchTemplate()

  img_gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
  res = cv2.matchTemplate(image=img_gray,templ=kernel_b,method=3)
  cv2.imwrite('res_match_template.tiff',res)
  min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
  # print values from above

  # Drawing Bounding Box around detected shape
  # determine the starting and ending (x, y)-coordinates of the bounding box
  # From: https://www.pyimagesearch.com/2021/03/22/opencv-template-matching-cv2-matchtemplate/
  (startX, startY) = max_loc
  endX = startX + kernel_b.shape[1]
  endY = startY + kernel_b.shape[0]

  # draw the bounding box on the image
  b_box_image = cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 1)
MohammadKhan-3 commented 2 years ago

Testing MatchTemplate() with Pixelated Diamonds

MohammadKhan-3 commented 2 years ago

Testing MatchTemplate() with Tic-Tac-Toe

MatchTemplate_Tic-tac-toe-STRAIGHT e

MohammadKhan-3 commented 2 years ago

Testing MatchTemplate() with Tic-Tac-Toe Angled orientation

MatchTemplate_Tic-tac-toe-ANGLED

Blue Square Crop:

blue_square_crop

Code for both Straight & Angled Orientation:

# Reading image
image = cv2.imread("tic_tac_toe_images/twistCorrectedColoredSquares_Color.tiff")
# For straight orientation use: image = cv2.imread("tic_tac_toe_images/CorrectedColoredSquares_Color.tiff")

# creating blue square crop as kernel
kernel_b = cv2.imread('tic_tac_toe_images/blue_square_crop.tiff')

res = cv2.matchTemplate(image=image,templ=kernel_b,method=3)
cv2.imwrite('res_match_template.tiff',res)

cv::TemplateMatchModes cv::TM_SQDIFF = 0, cv::TM_SQDIFF_NORMED = 1, cv::TM_CCORR = 2, cv::TM_CCORR_NORMED = 3, cv::TM_CCOEFF = 4, cv::TM_CCOEFF_NORMED = 5

MohammadKhan-3 commented 2 years ago

Using different methods of MatchTemplate() with Tic-Tac-Toe Angled & Straight Orientation

Looking more into the methods offered by MatchTemplate()

Next Steps:

MohammadKhan-3 commented 2 years ago

Match template: Recognizing all 3 Squares

Interesting to note is that if you do multiple Match Template functions in the same script, multiple bounding boxes can be drawn on one image. However, the heat map shown below is the last one in the code (in this case, the green box heatmap)

MatchTemplate_ALL 3 Squares_METHOD5_ANGLED

Code:

# Read Image into script
image = cv2.imread("tic_tac_toe_images/twistCorrectedColoredSquares_Color.tiff")

# Creating Kernels from cropped images
kernel_b = cv2.imread('tic_tac_toe_images/blue_square_crop.tiff')    # blue square detection
kernel_r = cv2.imread('tic_tac_toe_images/red_square_crop.tiff')      # red square detection
kernel_g = cv2.imread('tic_tac_toe_images/green_square_crop.tiff') # green square detection

# MatchTemplate()
res_B = cv2.matchTemplate(image=image,templ=kernel_b,method=5)
cv2.imwrite('res_match_template_B.tiff',res_B)
min_val_B, max_val_B, min_loc_B, max_loc_B = cv2.minMaxLoc(res_B)
print('min_loc_B')
print(min_loc_B)
print('max_loc_B')
print(max_loc_B)

# Drawing Bounding Box around detected shape
# determine the starting and ending (x, y)-coordinates of the bounding box
# From: https://www.pyimagesearch.com/2021/03/22/opencv-template-matching-cv2-matchtemplate/
(startX_B, startY_B) = max_loc_B
endX_B = startX_B + kernel_b.shape[1]
endY_B = startY_B + kernel_b.shape[0]

# draw the bounding box on the image (same process for green & red boxes)
b_box_image = cv2.rectangle(image, (startX_B, startY_B), (endX_B, endY_B), (255, 0, 0), 4) # BGR for openCV
# show the output image
# cv2.imshow("Output based on matchTemplate", b_box_image)
cv2.imwrite('res_match_template_Blue_BoundingBox.tiff', b_box_image)

Next Steps:

acbuynak commented 2 years ago

we use 4.2, so need to test on that version of opencv

Is there any reason we can't use the newer version of opencv? My understanding of the OpenCV version choice was arbitrary.

MohammadKhan-3 commented 2 years ago

Making MatchTemplate more applicable to general scenarios:

Next Steps:

MohammadKhan-3 commented 2 years ago

Notes on MatchTemplate():

java.lang.NegativeArraySizeException at ij.io.ImageReader.readCompressed32bitImage(ImageReader.java:271) at ij.io.ImageReader.read32bitImage(ImageReader.java:203) at ij.io.ImageReader.readPixels(ImageReader.java:788) at ij.io.FileOpener.readPixels(FileOpener.java:541) at ij.io.FileOpener.open(FileOpener.java:96) at ij.io.FileOpener.openImage(FileOpener.java:53) at ij.io.Opener.openTiff2(Opener.java:1039) at ij.io.Opener.openTiff(Opener.java:842) at ij.io.Opener.openImage(Opener.java:317) at ij.io.Opener.openImage(Opener.java:243) at ij.io.Opener.open(Opener.java:109) at ij.io.Opener.open(Opener.java:72) at ij.plugin.Commands.run(Commands.java:27) at ij.IJ.runPlugIn(IJ.java:204) at ij.Executer.runCommand(Executer.java:150) at ij.Executer.run(Executer.java:68) at java.lang.Thread.run(Thread.java:745)

- I think the error lies in creating a 3 depth array to use as a kernel. Here is the current method of making the 3 depth array:

Create kernel (format - "BGR")

kernel_size = 5 print('Shape of Input image') print(np.shape(image))

Uncomment below to create blue array

ch1 = 255*np.ones((kernel_size, kernel_size), dtype='uint8') ch2 = np.zeros((kernel_size, kernel_size), dtype='uint8') kernel_b = np.array([ch1, ch2, ch2], ndmin=3, dtype='uint8')

might be BGR

print('Kernel Matrix: should be 3x3x3') print(np.shape(kernel_b)) # returns 3x3x3 print(kernel_b)

**Output:**

Shape of image (50, 50, 3) Kernel Matrix: should be 5x5x3 (3, 5, 5) [[[255 255 255 255 255] [255 255 255 255 255] [255 255 255 255 255] [255 255 255 255 255] [255 255 255 255 255]]

[[ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0]]

[[ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0] [ 0 0 0 0 0]]]


## Next Steps: 
- Look into Numpy Array docs for creating a 3D Array
- https://www.kite.com/python/answers/how-to-create-a-3d-numpy-array-in-python
- https://numpy.org/doc/stable/reference/generated/numpy.array.html
- 
MohammadKhan-3 commented 2 years ago

Looking into Numpy Arrays & Shape function

Numpy Array: https://numpy.org/doc/stable/reference/generated/numpy.array.html

Numpy Shape: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html

MohammadKhan-3 commented 2 years ago

Looking more into cv2.matchtemplate():

openCV docs: https://docs.opencv.org/4.2.0/d4/dc6/tutorial_py_template_matching.html

Process for using matchTemplate():

If matchTemplate() doesn't work: look into other color detection methods

MohammadKhan-3 commented 2 years ago

Plan for completing Tic-Tac-Toe Project:

Creating General Use of matchTemplate()

MohammadKhan-3 commented 2 years ago

Live Camera feed with MatchTemplate() function

Recognizing objects at different scales:

More importantly, the use a live camera feed:

#Camera 
cap = cv2.VideoCapture(0)

#symbool inladen
symbool = cv2.imread('klaver.jpg',0)
w, h = symbool.shape[::-1]

while(1):
    res, frame = cap.read()

In my case, I am subscribing to a rostopic. image_sub = rospy.Subscriber("/camera/color/image_raw", Image, runner) However, I could forgo subscribing to the topic and access the camera feed directly since the script does not need to pull from the image topic. The purpose of the script is to recognize where the squares are and output the centers and orientation so the robot can make the appropriate movements to play the game.

Action Items:

acbuynak commented 2 years ago

However, I could forgo subscribing to the topic and access the camera feed directly since the script does not need to pull from the image topic.

Heads up, I don't think it's possible to have both a ROS-based camera feed AND a python-based feed open at the same time. I don't remember ever testing this specifically, but I assume due to the handshake between the camera and computer that it might not let you initiate the second stream.

MohammadKhan-3 commented 2 years ago

However, I could forgo subscribing to the topic and access the camera feed directly since the script does not need to pull from the image topic.

Heads up, I don't think it's possible to have both a ROS-based camera feed AND a python-based feed open at the same time. I don't remember ever testing this specifically, but I assume due to the handshake between the camera and computer that it might not let you initiate the second stream.

Ok. I'll see if it can be done. Just to clarify I was going to remove the ros topic and ros imports and use just cv2.VideoCapture() for accessing the camera feed.

acbuynak commented 2 years ago

Just to clarify I was going to remove the ros topic and ros imports and use just cv2.VideoCapture() for accessing the camera feed.

Gotcha. No worries, just wanted to help catch anything before we got there.

MohammadKhan-3 commented 2 years ago

Potential Solution to cv2.VideoCapture() issues

This Stack Overflow post helped solve it: https://stackoverflow.com/questions/52029233/how-to-make-usb-camera-work-with-opencv

TLDR: Plug in the camera, go to your terminal home

When I plugged in iRS#2 camera and cd /dev with the above steps, I had video0, video1, video2, video3, video4, video5 appear. I found that cv2.VideoCapture(4) worked.

MohammadKhan-3 commented 2 years ago

Live Video feed using cv2.Video Capture: Image is dark

Tried adding a time.sleep() but even at time.sleep(30), the image remains dark. Image is shown below Screenshot from 2022-01-19 10-33-36

Here is the code I am using:

        cap = cv2.VideoCapture(4)
        # refer to this github issue for why I used VideoCapture(4)
        # https://github.com/OSU-AIMS/tic-tac-toe/issues/10#issuecomment-1016505927

        # allowing the camera time to boot up and auto set exposure
        time.sleep(30) # seconds

        while(1):
            res,frame = cap.read()
            frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
            kernel_runner(frame)
        cap.release()

Opening the camera in Intel Realsense viewer is fine. The video feed brightens up within 1 sec.

Action Items:

MohammadKhan-3 commented 2 years ago

MatchTemplate: needs to be more robust

Screenshot from 2022-01-24 09-52-21

To make MatchTemplate() more robust detection will need to look into keypoint detectors, local invariant descriptors and keypoint matching to detect changes in scale, rotation, lighting, etc in the image.

Note:

Next Steps:

Potential Local Invariant Descriptors & Keypoint Matching methods to look into: SIFT, SURF, FREAK, RANSAC

@acbuynak if you've heard of any these before or any suggestions on which to start with, let me know.

acbuynak commented 2 years ago

Responses

Using the kernels for the static image will not work in the above dynamic environment because the distance from the board to the camera is different which results in the colored squares being different sizes in the camera feed.

Understood. let's assume a sufficiently static environment for now where the board will always be a fixed z-distance from the camera. Before we jump onto making this more adjustable, let's run the techniques past some vision experts to get ideas/guidance first. See last note.

MatchTemplate() is sensitive to rotation, scaling, lighting, camera focal length. What works in one setting, may not work in another if the environment are different.

Makes sense, our first draft implementation is going to be rough.

@acbuynak if you've heard of any these before or any suggestions on which to start with, let me know.

Nope. These are all new to me, but let's pause on robustness if it's working even slightly at this point. We could run them past mgroeber to see if he recognizes them later.


Next Steps

Let's hold off for now. I'd rather have you help Luis to get the rest of the structure setup. Even if the vision is only working sometimes.. that's okay. We just want a basic prototype before proceeding.

MohammadKhan-3 commented 2 years ago

Final results:

Screenshot from 2022-01-31 10-06-12

Using MatchTemplate(), able to recognize 3 colors with a decent accuracy. Not perfect --> lighting, rotation, and other dynamic conditions still affect detection

Issues:

For more info on Object detection Methods and making MatchTemplate() more robust. See the Object Detection Wiki Page in the right panel: https://github.com/OSU-AIMS/tic-tac-toe/wiki