问题
Problem
I am processing an iPhone screen recording of a game automatic replay called Chinese Chess (I press the play button once, it automatically goes through all the moves). The screen recording is in 30FPS, and conveniently, every second (30 frames), a new move is made.
For example, the 120th frame looks like this:
30 frames (1 second) later, the 150th frame looks like this:
I want to detect each move played by comparing the previous frame to the current frame. My code works if the piece moves more than one square, but if it only moves one square (like in this example above), the 2 contours get merged together (looks like a snowman): (Please ignore the rectangles)
This is what I actually want:
Two separate, circular contours, indicating the original square of the piece and the new square of the piece.
Note that, because of the shadow and the white ring, the contour for the new square is bigger than the original square This is important because it allows me to identify the contours using cv2.contourArea
Code
#previous_frame and current_frame are frames from cv2.VideoCapture()
imageA = previous_frame #the original square
imageB = current_frame #the new square
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
# Structural Similarity Index (SSIM)
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #I am using openCV4
cnts.sort(key=cv2.contourArea, reverse=True) #sort by decreasing order of size
cv2.drawContours(imageB, cnts, 0, (0,0,255), 10) #new coordinate is the largest contour, hence index 0
cv2.drawContours(imageA, cnts, 1, (0,0,255), 10) #original is second largest, hence index 1
I have tried using approxPolyDP
and minEnclosingCircle
but no luck.
来源:https://stackoverflow.com/questions/63460584/how-to-split-a-snowman-shaped-contour-into-two-circles