Skip to content

Instantly share code, notes, and snippets.

@JT5D
Forked from martinsik/circle_detection.py
Created February 9, 2017 04:41
Show Gist options
  • Save JT5D/e9f27ae67691611e2eaff75762664607 to your computer and use it in GitHub Desktop.
Save JT5D/e9f27ae67691611e2eaff75762664607 to your computer and use it in GitHub Desktop.
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;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment