Skip to content

Instantly share code, notes, and snippets.

@martinsik
Last active April 22, 2023 09:50
Show Gist options
  • Save martinsik/a3d6142b0392d77c13ab to your computer and use it in GitHub Desktop.
Save martinsik/a3d6142b0392d77c13ab 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;
};
@akssieg
Copy link

akssieg commented Apr 4, 2022

Everything is working after doing some modifications but video is not rendering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment