MDTexField Color when is normal kivy - kivy

I would like the color of MDTextField to be the same when it is disabled, but I donĀ“t know how I can achieve it.
def escribir_sumandos(self, mas):
for i in range(0,self.num_fil):
for j in range(0,self.num_col):
if (i == 0 and j >= (7-mas)) or (i == self.num_fil-1 and j >= (7-mas)):
self.texto = MDTextField(
input_type = "number",
halign ="center",
text_color = (1.0, 1.0, 1.0, 1),
)

Related

i can't grab frame 2 object has no attribute

i want to make a separate tracking but the total inside is the sum of each track but it just keep giving me frame2 = imutils.resize(frame2, width = 500)
pture_MSMF::grabFr File "D:\pyli\lib\site-packages\imutils\convenience.py", line 69, in resize
ame videoio(MSMF): can't grab frame. Error: -2147023901
(h, w) = image.shape[:2].
from mylib.centroidtracker import CentroidTracker
from mylib.trackableobject import TrackableObject
from imutils.video import VideoStream
from imutils.video import FPS
from mylib.mailer import Mailer
from mylib import config, thread
import time, schedule, csv
import numpy as np
import argparse, imutils
import time, dlib, cv2, datetime
from itertools import zip_longest
t0 = time.time()
def run():
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=False,
help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
help="path to Caffe pre-trained model")
ap.add_argument("-i", "--input", type=str,
help="path to optional input video file")
ap.add_argument("-o", "--output", type=str,
help="path to optional output video file")
ap.add_argument("-c", "--confidence", type=float, default=0.4,
help="minimum probability to filter weak detections")
ap.add_argument("-s", "--skip-frames", type=int, default=30,
help="# of skip frames between detections")
args = vars(ap.parse_args())
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
"sofa", "train", "tvmonitor"]
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
net2 = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
if not args.get("input", False):
print("[INFO] Starting live cam 1 & 2..")
vs = VideoStream(config.url).start()
vs2 = VideoStream(config.url1).start()
time.sleep(2.0)
writer = None
W = None
H = None
ct = CentroidTracker(maxDisappeared=10, maxDistance=100)
trackers = []
trackableObjects = {}
ct2 = CentroidTracker(maxDisappeared=10, maxDistance=100)
trackers2 = []
trackableObjects2 = {}
totalFrames = 0
totalDown = 0
totalUp = 0
x = []
empty=[]
empty1=[]
totalFrames2 = 0
totalDown2 = 0
totalUp2 = 0
x2 = []
empty2=[]
empty3=[]
fps = FPS().start()
if config.Thread:
vs = thread.ThreadingClass(config.url)
vs2 = thread.ThreadingClass(config.url1)
while True:
frame = vs.read()
frame = frame[1] if args.get("input", False) else frame
frame2 = vs2.read()
frame2 = frame2[1] if args.get("input", False) else frame2
frame = imutils.resize(frame, width = 500)
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame2 = imutils.resize(frame2, width = 500)
rgb2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2RGB)
if W is None or H is None:
(H, W) = frame.shape[:2]
(H, W) = frame2.shape[:2]
status = "Waiting"
rects = []
status2 = "Waiting"
rects2 = []
if totalFrames % args["skip_frames"] == 0:
status = "Detecting"
trackers = []
blob = cv2.dnn.blobFromImage(frame, 0.007843, (W, H), 127.5)
net.setInput(blob)
detections = net.forward()
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > args["confidence"]:
idx = int(detections[0, 0, i, 1])
if CLASSES[idx] != "person":
continue
box = detections[0, 0, i, 3:7] * np.array([W, H, W, H])
(startX, startY, endX, endY) = box.astype("int")
tracker = dlib.correlation_tracker()
rect = dlib.rectangle(startX, startY, endX, endY)
tracker.start_track(rgb, rect)
trackers.append(tracker)
else:
for tracker in trackers:
status = "Tracking"
tracker.update(rgb)
pos = tracker.get_position()
startX = int(pos.left())
startY = int(pos.top())
endX = int(pos.right())
endY = int(pos.bottom())
rects.append((startX, startY, endX, endY))
if totalFrames2 % args["skip_frames"] == 0:
status2 = "Detecting"
trackers2 = []
blob2 = cv2.dnn.blobFromImage(frame2, 0.007843, (W, H), 127.5)
net2.setInput(blob2)
detections2 = net2.forward()
for i in np.arange(0, detections2.shape[2]):
confidence2 = detections2[0, 0, i, 2]
if confidence2 > args["confidence"]:
idx2 = int(detections2[0, 0, i, 1])
if CLASSES[idx2] != "person":
continue
box2 = detections2[0, 0, i, 3:7] * np.array([W, H, W, H])
(startX2, startY2, endX2, endY2) = box2.astype("int")
trackers2 = dlib.correlation_tracker()
rects2 = dlib.rectangle(startX2, startY2, endX2, endY2)
tracker2.start_track(rgb2, rects2)
trackers2.append(tracker2)
else:
for tracker2 in trackers2:
status2 = "Tracking"
tracker2.update(rgb2)
pos2 = tracker2.get_position()
startX2 = int(pos2.left())
startY2 = int(pos2.top())
endX2 = int(pos2.right())
endY2 = int(pos2.bottom())
rects2.append((startX2, startY2, endX2, endY2))
cv2.line(frame, (0, H // 2), (W, H // 2), (0, 0, 0), 3)
cv2.putText(frame, "-Prediction border - Entrance-", (10, H - ((i * 20) + 200)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
cv2.line(frame2, (0, H // 2), (W, H // 2), (0, 0, 0), 3)
cv2.putText(frame2, "-Prediction border - Entrance-", (10, H - ((i * 20) + 200)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
objects = ct.update(rects)
objects2 = ct2.update(rects2)
for (objectID, centroid) in objects.items():
to = trackableObjects.get(objectID, None)
if to is None:
to = TrackableObject(objectID, centroid)
else:
y = [c[1] for c in to.centroids]
direction = centroid[1] - np.mean(y)
to.centroids.append(centroid)
if not to.counted:
if direction < 0 and centroid[1] < H // 2:
totalUp += 1
empty.append(totalUp)
to.counted = True
elif direction > 0 and centroid[1] > H // 2:
totalDown += 1
empty1.append(totalDown)
if sum(x) >= config.Threshold:
cv2.putText(frame, "-ALERT: People limit exceeded-", (10, frame.shape[0] - 80),
cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255), 2)
if config.ALERT:
print("[INFO] Sending email alert..")
Mailer().send(config.MAIL)
print("[INFO] Alert sent")
to.counted = True
x = []
x.append(len(empty1)-len(empty))
trackableObjects[objectID] = to
text = "ID {}".format(objectID)
cv2.putText(frame, text, (centroid[0] - 10, centroid[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
cv2.circle(frame, (centroid[0], centroid[1]), 4, (255, 255, 255), -1)
for (objectID2, centroid2) in objects2.items():
to2 = trackableObjects2.get(objectID2, None)
if to2 is None:
to2 = TrackableObject(objectID2, centroid2)
else:
y2 = [c[1] for c in to2.centroids]
direction2 = centroid2[1] - np.mean(y2)
to2.centroids.append(centroid2)
if not to2.counted2:
if direction2 < 0 and centroid2[1] < H // 2:
totalUp2 += 1
empty2.append(totalUp2)
to2.counted2 = True
elif direction2 > 0 and centroid2[1] > H // 2:
totalDown2 += 1
empty3.append(totalDown2)
if sum(x) >= config.Threshold:
cv2.putText(frame2, "-ALERT: People limit exceeded-", (10, frame2.shape[0] - 80),
cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255), 2)
if config.ALERT:
print("[INFO] Sending email alert..")
Mailer().send(config.MAIL)
print("[INFO] Alert sent")
to2.counted2 = True
x2 = []
x2.append(len(empty3)-len(empty2))
trackableObjects2[objectID2] = to2
text2 = "ID2 {}".format(objectID2)
cv2.putText(frame2, text2, (centroid2[0] - 10, centroid2[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
cv2.circle(frame2, (centroid2[0], centroid2[1]), 4, (255, 255, 255), -1)
info = [
("Exit", totalUp),
("Enter", totalDown),
("Status", status),
]
info3 = [
("Total people inside", x+x2),
]
info2 = [
("Exit", totalUp2),
("Enter", totalDown2),
("Status", status2),
]
for (i, (k, v)) in enumerate(info):
text = "{}: {}".format(k, v)
cv2.putText(frame, text, (10, H - ((i * 20) + 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
for (i, (k, v)) in enumerate(info3):
text = "{}: {}".format(k, v)
cv2.putText(frame, text, (265, H - ((i * 20) + 60)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
text2 = "{}: {}".format(k, v)
cv2.putText(frame2, text2, (265, H - ((i * 20) + 60)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
for (i, (k, v)) in enumerate(info2):
text2 = "{}: {}".format(k, v)
cv2.putText(frame2, text2, (265, H - ((i * 20) + 60)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
if config.Log:
datetimee = [datetime.datetime.now()]
d = [datetimee, empty1+empty3, empty+empty2, x+x2]
export_data = zip_longest(*d, fillvalue = '')
with open('Log.csv', 'w', newline='') as myfile:
wr = csv.writer(myfile, quoting=csv.QUOTE_ALL)
wr.writerow(("End Time", "In", "Out", "Total Inside"))
wr.writerows(export_data)
if writer is not None:
writer.write(frame)
writer.write(frame2)
cv2.imshow("Real-Time Monitoring/Analysis Window", frame)
cv2.imshow("Real-Time Monitoring 2", frame2)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
totalFrames += 1
totalFrames2 += 1
fps.update()
if config.Timer:
t1 = time.time()
num_seconds=(t1-t0)
if num_seconds > 28800:
break
fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
if config.Thread:
vs.release()
vs2.release()
cv2.destroyAllWindows()
if config.Scheduler:
schedule.every().day.at("09:00").do(run)
while 1:
schedule.run_pending()
else:
run()

Want to improve the love2d code for performance

I am making a platformer where i am generating level with below code:
function LevelMaker.generateLevel3(width, height)
local tiles = {}
local objects = {}
local entities = {}
for y = 1, height do
table.insert(tiles, {})
for x = 1, width do
if y == 9 and (x > 5 and x < 12) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 12) and (x > 11 and x < 30) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 3) and (x == 13) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 17) and (x > 15 and x < 28) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 9) and (x > 31 and x < 35) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 6) and (x > 25 and x < 29) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y > 1 and y < 7) and (x == 26) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 0) and (x > 3 and x < 10) then
table.insert(tiles[y], Tile(x, y, math.random(1, 3)))
elseif (y == 13) and (x > 22 and x < 30) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 2,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y == 3) and (x == 12) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 4,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y == 2 or y == 4) and (x == 13) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = y == 2 and 1 or 2,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y == 8) and (x == 10 or x == 11) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 1,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y > 1 and y < 7) and (x == 25) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 4,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y == 8) and (x == 34) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 1,
collidable = true,
solid = true,
deadly = true
}
)
elseif (y == 1) and (x > 3 and x < 10) then
table.insert(tiles[y], Tile(x, y, SKY))
table.insert(objects,
GameObject{
texture = 'spikes',
x = (x - 1) * TILE_SIZE, y = (y - 1) * TILE_SIZE,
width = TILE_SIZE, height = TILE_SIZE,
frame = 2,
collidable = true,
solid = true,
deadly = true
}
)
else
table.insert(tiles[y], Tile(x, y, SKY))
end
end
end
table.insert(objects,
GameObject{
texture = 'house',
x = (16 - 1) * TILE_SIZE, y = (13 - 1) * TILE_SIZE,
width = 36, height = 44,
frame = 1,
}
)
table.insert(objects,
GameObject{
texture = 'gems',
x = (28 - 1) * TILE_SIZE, y = (5 - 1) * TILE_SIZE,
width = 15, height = 11,
frame = {1,2,3,4,5},
}
)
local map = TileMap(width, height)
map.tiles = tiles
return GameLevel(entities, objects, map)
end
Is there a way to improve the same above code (improve time complexity)
When the player dies over and over within 1-2 sec the game freezes.
I want to load the level as fast as possible
What sticks out to me is that you're running two nested for loops over X and Y just to draw a couple lines, then checking whether the points are on the line using range checks to eventually place tiles; the only thing that seems to be randomized is the tile type, but not the tile position. You should store a list of lines and draw each line on the screen with randomized tiles:
for y = 1, height do -- prepare the grid
table.insert(tiles, {})
end
local lines = {{from = 6, to = 11, y = 9}, {from = ..., to = ...}, {...}, ...}
for _, line in pairs(lines) do -- draw lines
if line.y then
for x = line.from, line.to do
table.insert(tiles[line.y], Tile(x, line.y, math.random(1, 3)))
end
elseif line.x then
for y = line.from, line.to do
table.insert(tiles[y], Tile(line.x, y, math.random(1, 3)))
end
end
end
the fixed sky/spikes/house/gems tiles can benefit from the same technique; you'll have to store a line tile type with each line and use it instead of the random tile though. These seem to be static though - why can't you just reuse the old level and replace only the randomized tiles using the described "line drawing" technique?

Intersection in an array of rectangles OpenCv

I try to detect certain moving objects in a video. If any two/three+ rectangles overlap/intersect I want them to change the color.
I have tried something like this:
for (size_t i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0.0, 255.0, 0.0);
// intersection
original = boundRect[i];
for (size_t j = 0; j < boundRect.size(); j++){
if (j == i) continue; // the same rectangle
match = boundRect[j];
if ((original & match).area() > 0) color = Scalar(0.0, 0.0, 255.0);
else color = Scalar(0.0, 255.0, 0.0);
}
// draw the rectangle
rectangle(frame, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
}
It does work sometime, but now always. I don't know if I am doing it right or if there is any better way to do that.
You seem to compute intersects the right way, but you only draw the results once for each i. And if a rectangle j doesn't intersect i you'll overwrite your changed color again. Just remove the else case for setting the color, OR remember whether (or how often) a rectangle intersects another one. For example:
for (size_t i = 0; i < contours.size(); i++)
{
int nIntersections = 0;
// intersection
original = boundRect[i];
for (size_t j = 0; j < boundRect.size(); j++){
if (j == i) continue; // the same rectangle
match = boundRect[j];
if ((original & match).area() > 0)
{
nIntersections++;
// if you only want to know whether intersections appear or not, you can stop the inner for-loop here, by using j=boundRect.size(); continue; or break;
}
}
// draw the rectangle
cv::Scalar color(0,255,0);
if(nIntersections > 0) color = cv::Scalar(0,0,255);
// adjust for different
// if(nIntersections > 1) color = ...
rectangle(frame, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
// for simplicity you can just call rectangle(frame, boundRect[i], color, 2, 8, 0); without getting top-left and bottom-right points first. cv::rectangle uses cv::Rect as a parameter directly if you like.
}
if you however want to draw each intersection area, it's getting a bit more complicated, but can be done, too...

How to get a color range from a "Drag Box" in OpenCV 2.4

I'm using Python and OpenCV 2.4. I'm trying to get a HSV average from an area selected by dragging the mouse, much like in the camShift example provided by OpenCV. But I want the X, Y of the selected color instances in a video feed.
I've been hacking at the onmouse function in camShift. I feel it is close to want I want, I just can't seem to extract the mean HSV values of the area selected. I know I could probably get this done with a for loop, but trying to make it as responsive as possible.
def onmouse(self, event, x, y, flags, param):
x, y = np.int16([x, y]) # BUG
if event == cv2.EVENT_LBUTTONDOWN:
self.drag_start = (x, y)
self.tracking_state = 0
if self.drag_start:
if flags & cv2.EVENT_FLAG_LBUTTON:
h, w = 480, 640 # self.frame.shape[:2]
xo, yo = self.drag_start
x0, y0 = np.maximum(0, np.minimum([xo, yo], [x, y]))
x1, y1 = np.minimum([w, h], np.maximum([xo, yo], [x, y]))
self.selection = None
if x1-x0 > 0 and y1-y0 > 0:
self.selection = (x0, y0, x1, y1)
else:
self.drag_start = None
if self.selection is not None:
self.tracking_state = 1
Ok. It's crude, but this seems to be a lot closer than I was:
import numpy as np
import cv2
import video
class App(object):
def __init__(self, video_src):
#self.cam = video.create_capture(video_src)
self.cam = cv2.VideoCapture(0)
ret, self.frame = self.cam.read()
cv2.namedWindow('camshift')
cv2.setMouseCallback('camshift', self.onmouse)
self.selection = None
self.drag_start = None
self.tracking_state = 0
self.show_backproj = False
def onmouse(self, event, x, y, flags, param):
x, y = np.int16([x, y]) # BUG
if event == cv2.EVENT_LBUTTONDOWN:
self.drag_start = (x, y)
self.tracking_state = 0
if self.drag_start:
if flags & cv2.EVENT_FLAG_LBUTTON:
h, w = self.frame.shape[:2]
xo, yo = self.drag_start
x0, y0 = np.maximum(0, np.minimum([xo, yo], [x, y]))
x1, y1 = np.minimum([w, h], np.maximum([xo, yo], [x, y]))
self.selection = None
if x1-x0 > 0 and y1-y0 > 0:
self.selection = (x0, y0, x1, y1)
else:
self.drag_start = None
if self.selection is not None:
self.tracking_state = 1
def show_hist(self):
bin_count = self.hist.shape[0]
bin_w = 24
img = np.zeros((256, bin_count*bin_w, 3), np.uint8)
for i in xrange(bin_count):
h = int(self.hist[i])
cv2.rectangle(img, (i*bin_w+2, 255), ((i+1)*bin_w-2, 255-h), (int(180.0*i/bin_count), 255, 255), -1)
img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR)
cv2.imshow('hist', img)
def run(self):
while True:
ret, self.frame = self.cam.read()
self.frame = cv2.blur(self.frame,(3,3))
vis = self.frame.copy()
hsv = cv2.cvtColor(self.frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
mask2 = mask.copy()
if self.selection:
x0, y0, x1, y1 = self.selection
self.track_window = (x0, y0, x1-x0, y1-y0)
hsv_roi = hsv[y0:y1, x0:x1]
mask_roi = mask[y0:y1, x0:x1]
#cv2.norm(hsv_roi)
dHSV = cv2.mean(hsv_roi)
h, s, v = int(dHSV[0]), int(dHSV[1]), int(dHSV[2])
hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] )
cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX);
self.hist = hist.reshape(-1)
self.show_hist()
vis_roi = vis[y0:y1, x0:x1]
cv2.bitwise_not(vis_roi, vis_roi)
vis[mask == 0] = 0
if self.tracking_state == 1:
self.selection = None
cv2.imshow('camshift', vis)
if self.tracking_state == 1:
if h > 159:
h = 159
if s > 235:
s = 235
if v > 235:
v = 235
if h < 20:
h = 20
if s < 20:
s = 20
if v < 20:
v = 20
thresh = cv2.inRange(hsv,np.array(((h-20), (s-20), (v-20))), np.array(((h+20), (s+20), (v+20))))
thresh2 = thresh.copy()
# find contours in the threshold image
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#best_cnt = 1
max_area = 0
for cnt in contours:
area = cv2.contourArea(cnt)
if area > max_area:
max_area = area
best_cnt = cnt
# finding centroids of best_cnt and draw a circle there
M = cv2.moments(best_cnt)
cx,cy = int(M['m10']/M['m00']), int(M['m01']/M['m00'])
print cx, cy
cv2.circle(thresh2,(cx,cy),20,255,-1)
cv2.imshow('thresh',thresh2)
ch = 0xFF & cv2.waitKey(5)
if ch == 27:
break
if ch == ord('b'):
self.show_backproj = not self.show_backproj
cv2.destroyAllWindows()
if __name__ == '__main__':
import sys
try: video_src = sys.argv[1]
except: video_src = 0
print __doc__
App(video_src).run()
I hack-sawed Rahman's example and camShift

Orientation of non symmetrical a shape in Emgu or OpenCv

I'm trying to obtain the orientation of a shape (binary or contour). The shape is mostly rectangular but has a large hole on one side. I want my orientation to be consistent with this assymetry in the object.
I've been looking at several articles that use the spatial and central moments for this. E.g.
Binary Image Orientation
but it seems that the orientation I get with this is sometimes off with a multiple of 90 degrees.
The following document states that there is some ambiguity:
http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf
If I implement this using
private void GetCenterAndOrientationViaMoments(Contour<Point> cont, Size imageSize)
{
// obtain the orientation of the found object
// first draw the binary blob in a separate image
// I do this for the hole(s) in the image, but I'm not sure if it is needed.
// Possibly I can tak the moments directly from the contour
Image<Gray, byte> instanceImage = new Image<Gray, byte>(imageSize);
instanceImage.FillConvexPoly(cont.ToArray(), new Gray(255));
for (Contour<Point> hole = cont.VNext;
hole != null;
hole = hole.HNext)
instanceImage.FillConvexPoly(hole.ToArray(), new Gray(0));
// calculate the moments
MCvMoments m = instanceImage.GetMoments(true);
// MCvMoments m = cont.GetMoments();
double m00 = m.GetSpatialMoment(0, 0);
double m10 = m.GetSpatialMoment(1, 0);
double m01 = m.GetSpatialMoment(0, 1);
double mu11 = m.GetCentralMoment(1, 1);
double mu20 = m.GetCentralMoment(2, 0);
double mu02 = m.GetCentralMoment(0, 2);
// calculate the center
PointF center = new PointF((float)(m10 / m00), (float)(m01 / m00));
// calculate the orientation
// http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf
double theta = 0;
double mu20_mu02 = (mu20 - mu02);
if ((mu20_mu02 == 0) & (mu11 == 0))
theta = 0;
else if ((mu20_mu02 == 0) & (mu11 > 0))
theta = Math.PI / 4;
else if ((mu20_mu02 == 0) & (mu11 < 0))
theta = -Math.PI / 4;
else if ((mu20_mu02 > 0) & (mu11 == 0))
theta = 0;
else if ((mu20_mu02 < 0) & (mu11 == 0))
theta = -Math.PI / 2;
else if ((mu20_mu02 > 0) & (mu11 > 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
else if ((mu20_mu02 > 0) & (mu11 < 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
else if ((mu20_mu02 < 0) & (mu11 > 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) + Math.PI / 2;
else if ((mu20_mu02 < 0) & (mu11 < 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) - Math.PI / 2;
#if DEBUG
int radius = 25;
instanceImage.Draw(new CircleF(center, radius), new Gray(100), 2);
instanceImage.Draw(
new LineSegment2DF(
center,
new PointF(
(float)(center.X + radius * Math.Cos(theta)),
(float)(center.Y + radius * Math.Sin(theta)))),
new Gray(100),
2);
ImageViewer.Show(instanceImage, string.Format("Center and orientation"));
#endif
}
My orientation is correct, but does not always point to the same end of the object. In other words, I'm sometimes of by 180 degrees.
I'm guessing the method cannot provide exactly what I want because it uses the covariance of the distribution (http://en.wikipedia.org/wiki/Image_moments#Examples_2) which gives does not take into account the assymmetry caused by the hole, am I right?
Is there a way to resolve the 180 degrees ambiguity?
Regards,
Tom

Resources