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;
};
@prjoh
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
Copy link

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.

@tongclement
Copy link

tongclement commented Aug 12, 2020

A lot of bugs in 2020: What a pain to learn the library with
-no support for python3

  • a lot of depreciated commands
  • not properly documented for beginners, even with https://www.smashingmagazine.com/2016/02/simple-augmented-reality-with-opencv-a-three-js/
    1: Change all 'unicode' into 'str' in your python files because Unicode is renamed to Str (string) in python3
    2: you will get 'float errors' -> change w (width) from 360.0 to 360 and make add int(h) instead of h
    3: typo replace 'intersect' with 'intersects' (js file)
    4: change 3.js path to where you acutually install it. In the file, it is using lib/three.72.min.js , and I personally install it in js/three.js or js/three.min.js
    5: Uncaught TypeError: Cannot read property 'point' of undefined (not solved yet)
    .
    .
    .
    Not all issues are documented. Spending 5 hours fixing this buggy code is very annoying

@hoseinCode
Copy link

hi i need your videos and images

@EdwinFajardoBarrera
Copy link

A lot of bugs in 2020: What a pain to learn the library with
-no support for python3

  • a lot of depreciated commands
  • not properly documented for beginners, even with https://www.smashingmagazine.com/2016/02/simple-augmented-reality-with-opencv-a-three-js/
    1: Change all 'unicode' into 'str' in your python files because Unicode is renamed to Str (string) in python3
    2: you will get 'float errors' -> change w (width) from 360.0 to 360 and make add int(h) instead of h
    3: typo replace 'intersect' with 'intersects' (js file)
    4: change 3.js path to where you acutually install it. In the file, it is using lib/three.72.min.js , and I personally install it in js/three.js or js/three.min.js
    5: Uncaught TypeError: Cannot read property 'point' of undefined (not solved yet)
    .
    .
    .
    Not all issues are documented. Spending 5 hours fixing this buggy code is very annoying

Have u fixed the bugs?

@tongclement
Copy link

A lot of bugs in 2020: What a pain to learn the library with
-no support for python3

  • a lot of depreciated commands
  • not properly documented for beginners, even with https://www.smashingmagazine.com/2016/02/simple-augmented-reality-with-opencv-a-three-js/
    1: Change all 'unicode' into 'str' in your python files because Unicode is renamed to Str (string) in python3
    2: you will get 'float errors' -> change w (width) from 360.0 to 360 and make add int(h) instead of h
    3: typo replace 'intersect' with 'intersects' (js file)
    4: change 3.js path to where you acutually install it. In the file, it is using lib/three.72.min.js , and I personally install it in js/three.js or js/three.min.js
    5: Uncaught TypeError: Cannot read property 'point' of undefined (not solved yet)
    .
    .
    .
    Not all issues are documented. Spending 5 hours fixing this buggy code is very annoying

Have u fixed the bugs?

Hello Edwin! I was just returning to this project after so many months! Trying to reverse engineer the changes I made at the time and how to start the server (lol). I guess I was too mean at the time Haha. Anyways, I will update when I can get things working again. Hope it helps.

@ArchKeyTech
Copy link

@FalconBFR
Been messing about with this interesting project for a little while now taking things step by step.
so far i succeeded in having the globe move along with the mouse, however i replaced "earthMesh.position.x" and "earthMesh.position.y" with "earthMesh.position.copy()"
-instead of var mouse=[ ] and var ray = new THREE.Raycaster(camera.position, norm); i made it let mouse = new THREE.Vector2(); and raycaster = new THREE.Raycaster();
followed by let intersects = raycaster.intersectObject(tmpMesh);
these changes got rid of the "Uncaught TypeError: Cannot read property 'point' of undefined"

for the rest I am still clueless as to how the videocapture in opencv get displayed on the web page. Have you been able to make any progress?

@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