Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Circle detection with OpenCV 3.0
import cv2
import time
import math
import numpy as np
capture = cv2.VideoCapture(0)
print capture.get(cv2.CAP_PROP_FPS)
t = 100
w = 640.0
last = 0
while True:
ret, image = capture.read()
img_height, img_width, depth = image.shape
scale = w / img_width
h = img_height * scale
image = cv2.resize(image, (0,0), fx=scale, fy=scale)
# Apply filters
grey = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blured = cv2.medianBlur(grey, 15)
# Compose 2x2 grid with all previews
grid = np.zeros([2*h, 2*w, 3], np.uint8)
grid[0:h, 0:w] = image
# We need to convert each of them to RGB from grescaled 8 bit format
grid[h:2*h, 0:w] = np.dstack([cv2.Canny(grey, t / 2, t)] * 3)
grid[0:h, w:2*w] = np.dstack([blured] * 3)
grid[h:2*h, w:2*w] = np.dstack([cv2.Canny(blured, t / 2, t)] * 3)
cv2.imshow('Image previews', grid)
sc = 1
md = 30
at = 40
circles = cv2.HoughCircles(blured, cv2.HOUGH_GRADIENT, sc, md, t, at)
if circles is not None:
# We care only about the first circle found.
circle = circles[0][0]
x, y, radius = int(circle[0]), int(circle[1]), int(circle[2])
print(x, y, radius)
# Highlight the circle
cv2.circle(image, (x, y), radius, (0, 0, 255), 1)
# Draw dot in the center
cv2.circle(image, (x, y), 1, (0, 0, 255), 1)
cv2.imshow('Image with detected circle', image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
import cv2
import numpy as np
import threading
import json
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
server = None
clients = []
class SimpleWSServer(WebSocket):
def handleConnected(self):
clients.append(self)
def handleClose(self):
clients.remove(self)
def run_server():
global server
server = SimpleWebSocketServer('', 9000, SimpleWSServer,
selectInterval=(1000.0 / 15) / 1000)
server.serveforever()
t = threading.Thread(target=run_server)
t.start()
capture = cv2.VideoCapture(0)
t = 100
w = 640.0
last = 0
while True:
ret, image = capture.read()
img_height, img_width, depth = image.shape
scale = w / img_width
h = img_height * scale
image = cv2.resize(image, (0,0), fx=scale, fy=scale)
# Apply filters
grey = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blured = cv2.medianBlur(grey, 9)
# Compose 2x2 grid with all previews
grid = np.zeros([2*h, 2*w, 3], np.uint8)
grid[0:h, 0:w] = image
# We need to convert each of them to RGB from grescaled 8 bit format
grid[h:2*h, 0:w] = np.dstack([cv2.Canny(grey, t / 2, t)] * 3)
grid[0:h, w:2*w] = np.dstack([blured] * 3)
grid[h:2*h, w:2*w] = np.dstack([cv2.Canny(blured, t / 2, t)] * 3)
cv2.imshow('Image previews', grid)
sc = 1
md = 30
at = 40
circles = cv2.HoughCircles(blured, cv2.HOUGH_GRADIENT, sc, md, t, at)
if circles is not None:
# We care only about the first circle found.
circle = circles[0][0]
x, y, radius = int(circle[0]), int(circle[1]), int(circle[2])
print(x / w, y / h, radius / w)
# Highlight the circle
cv2.circle(image, (x, y), radius, (0, 0, 255), 1)
# Draw dot in the center
cv2.circle(image, (x, y), 1, (0, 0, 255), 1)
for client in clients:
client.sendMessage(unicode(json.dumps({'x': x / w, 'y': y / h, 'radius': radius / w})))
cv2.imshow('Image with detected circle', image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
server.close()
<html>
<body>
<style>
body { margin: 0; }
canvas { width: 100%; position: absolute; top: 0; }
video { width: 100%; }
</style>
<video autoplay></video>
<script src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/2.4.0/math.min.js"></script>
<script src="lib/three.72.min.js"></script>
<script src="main.js"></script>
</body>
</html>
var scene, camera, renderer, light;
var earthRotY = 0, moonRotY = 0;
var radY = 0, radZ = -0.3;
var moonDist = 70;
var earthRadius = 25;
var earthMesh, tmpMesh;
var moonMesh;
var positionHistory = [];
var lastPos, diffMove, lastEarthScale;
var ping = 0;
function init(width, height) {
scene = new THREE.Scene();
// Setup cameta with 45 deg field of view and same aspect ratio
var aspect = width / height;
camera = new THREE.PerspectiveCamera(45, aspect, 0.1, 1000);
// Set the camera to 400 units along `z` axis
camera.position.set(0, 0, 400);
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(width, height);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
}
function initLight() {
light = new THREE.SpotLight(0xffffff);
// Position the light slightly to a side to make
// shadows look better.
light.position.set(400, 100, 1000);
light.castShadow = true;
scene.add(light);
}
function initEarth() {
// Load Earth texture and create material from it
var earthTexture = THREE.ImageUtils.loadTexture("/images/earthmap1k.jpg");
earthTexture.minFilter = THREE.NearestFilter;
var earthMaterial = new THREE.MeshLambertMaterial({
map: earthTexture,
});
// Create a sphere 25 units in radius and 16 segments
// both horizontally and vertically.
var earthGeometry = new THREE.SphereGeometry(earthRadius, 16, 16);
earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
earthMesh.receiveShadow = true;
earthMesh.castShadow = true;
// Add Earth to the scene
scene.add(earthMesh);
}
function initMoon() {
var moonTexture = THREE.ImageUtils.loadTexture("/images/moonmap1k-lowres.jpg");
moonTexture.minFilter = THREE.NearestFilter;
var moonMaterial = new THREE.MeshLambertMaterial({
map: moonTexture,
});
var moonGeometry = new THREE.SphereGeometry(earthRadius * 0.273, 10, 10);
moonMesh = new THREE.Mesh(moonGeometry, moonMaterial);
moonMesh.receiveShadow = true;
moonMesh.castShadow = true;
scene.add(moonMesh);
}
function initPlane() {
// The plane needs to be large to be sure it'll always intersect
var tmpGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
tmpGeometry.position = new THREE.Vector3(0, 0, 0);
tmpMesh = new THREE.Mesh(tmpGeometry);
}
// Update position of objects in the scene
function update() {
if (positionHistory.length === 0) {
return;
}
earthRotY += 0.007;
ping++;
if (ping < 10) {
lastPos[0] += diffMove[0];
lastPos[1] += diffMove[1];
lastPos[2] += diffMove[2];
}
var vector = new THREE.Vector3(lastPos[0], lastPos[1], 0.5);
var intersect = checkIntersect(vector);
earthMesh.rotation.y = earthRotY;
// With position from OpenCV I could possibly move the Earth outside of the window
if (intersects.length === 1) {
var point = intersects[0].point;
earthMesh.position.x = point.x;
earthMesh.position.y = point.y;
// X pos + radius
var vector = new THREE.Vector3(lastPos[0] + lastPos[2], lastPos[1], 0.5);
var intersect = checkIntersect(vector);
var newEarthRadius = Math.abs(intersect.x - earthMesh.position.x);
var earthScale = newEarthRadius / earthRadius;
earthMesh.scale.set(earthScale, earthScale, earthScale);
moonMesh.scale.set(earthScale, earthScale, earthScale);
lastEarthScale = earthScale;
}
moonRotY += 0.005;
radY += 0.03;
radZ += 0.0005;
// Update Moon position
x = lastEarthScale * moonDist * Math.cos(radZ) * Math.sin(radY);
y = lastEarthScale * moonDist * Math.sin(radZ) * Math.sin(radY);
z = lastEarthScale * moonDist * Math.cos(radY);
moonMesh.position.set(x + earthMesh.position.x, y + earthMesh.position.y, z);
moonMesh.rotation.y = moonRotY;
}
function checkIntersect(vector) {
// Unproject camera distortion (fov, aspect ratio)
vector.unproject(camera);
var norm = vector.sub(camera.position).normalize();
var ray = new THREE.Raycaster(camera.position, norm);
// Cast a line from our camera to the tmpMesh and see where these
// two intersect. That's our 2D position in 3D coordinates.
var intersects = ray.intersectObject(tmpMesh);
return intersects[0].point;
}
// Redraw entire scene
function render() {
update();
renderer.setClearColor(0x000000, 0);
renderer.render(scene, camera);
// Schedule another frame
requestAnimationFrame(render);
}
//function onDocumentMouseMove(event) {
// // Current mouse position with [0,0] in the center of the document
// // and ranging from -1.0 to +1.0 with `y` axis inverted.
// mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
// mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
//}
document.addEventListener('DOMContentLoaded', function(event) {
// Initialize everything and start rendering
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
var video = document.querySelector('video');
var constrains = {
video: {
mandatory: {
minWidth: window.innerWidth,
}
}
};
if (navigator.getUserMedia) {
navigator.getUserMedia(constrains, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.oncanplay = function() {
init(video.clientWidth, video.clientHeight);
initEarth();
initMoon();
initLight();
initPlane();
requestAnimationFrame(render);
}
}, function() {});
}
});
var ws = new WebSocket('ws://localhost:9000');
ws.onopen = function() {
console.log('onopen');
};
ws.onmessage = function (event) {
var msg = JSON.parse(event.data);
positionHistory.push({
x: msg.x * 2 - 1,
y: - msg.y * 2 + 1,
radius: msg.radius
});
if (positionHistory.length > 10) {
positionHistory.shift();
}
var xCoords = [], yCoords = [], radiuses = [];
for (var i = math.max(positionHistory.length - 2, 0); i < positionHistory.length; i++) {
xCoords.push(positionHistory[i].x);
yCoords.push(positionHistory[i].y);
}
for (var i = 0; i < positionHistory.length; i++) {
radiuses.push(positionHistory[i].radius);
}
var posX = math.mean(xCoords);
var posY = math.mean(yCoords);
var radius = math.mean(radiuses);
var targetPos = [posX, posY, radius];
if (!lastPos) {
lastPos = targetPos;
}
diffMove = [(targetPos[0] - lastPos[0]) / 4, (targetPos[1] - lastPos[1]) / 4, (targetPos[2] - lastPos[2]) / 4]
ping = 0;
};
@prjoh

This comment has been minimized.

Copy link

prjoh commented Oct 27, 2018

Hello. How does 'lastPos' not diverge? I tried this code in a similar setup. Because 'lastPos' is incremented by 'diffMove' in line 83-85 and 'lastPos' is never reset, the coordinates begin to jump after several iterations. What am I missing?

@tomatopuree

This comment has been minimized.

Copy link

tomatopuree commented Dec 5, 2019

Where exactly in this snippet are the 3d models overlaid onto the webcam input ? I see that the init() takes the webcam input's dimensions for an aspect ratio but that seems to be it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.