Repository: HazSyl1/Virtual_Calculator
Branch: main
Commit: d6dbd7dd5264
Files: 8
Total size: 11.8 KB
Directory structure:
gitextract_mpzxbp6l/
├── .gitignore
├── Dockerfile
├── README.md
├── app.py
├── main.py
├── requirements.txt
├── static/
│ └── serve.js
└── templates/
└── index.html
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/virtualC
================================================
FILE: Dockerfile
================================================
FROM python:3.9-slim
WORKDIR /
COPY . .
RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
libopencv-dev \
&& rm -rf /var/lib/apt/lists/*
RUN pip install -r requirements.txt
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app"]
================================================
FILE: README.md
================================================
A virtual calculator build using OpenCV.
DEMO: https://www.youtube.com/watch?v=M8ZjUq8QD10
================================================
FILE: app.py
================================================
from flask import Flask,render_template,Response, jsonify , request
import cv2 as cv
from main import serve
import numpy as np
import base64
from flask_cors import CORS
app=Flask(__name__)
CORS(app)
# camera=cv.VideoCapture(2)
# camera.set(3,1280) #width
# camera.set(4,720) #height
history=[]
# def generate_frames():
# while True:
# success,frame=camera.read()
# if not success:
# break
# else:
# try:
# frame,finEq=serve(frame)
# except:
# pass
# if finEq!="":
# global history
# history.append(finEq)
# print(history)
# ret,buffer=cv.imencode('.jpg',frame)
# frame=buffer.tobytes()
# yield(b'--frame\r\n'
# b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/process_frame',methods=['POST'])
def process_frame():
try:
file=request.files['frame']
file_byte=np.frombuffer(file.read(),np.uint8)
frame=cv.imdecode(file_byte,cv.IMREAD_COLOR)
frame,finEq=serve(frame)
# print("GOT PROCESSED FILE")
_,buffer=cv.imencode('.jpg',frame)
processed_frame=base64.b64encode(buffer).decode('utf-8')
if finEq!="":
global history
history.append(finEq)
print(history)
return jsonify(success=True, frame =processed_frame)
except Exception as e:
print(e)
return jsonify(success=False,message=str(e))
@app.route('/get_history')
def update_history():
global history
print(history)
return jsonify(success=True,history=history)
@app.route('/')
def index():
# return "Starting"
global history
return render_template('index.html',history=history)
@app.route('/video')
def video_function():
return Response(generate_frames(),mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__=="__main__":
app.run(debug=True)
================================================
FILE: main.py
================================================
import cv2 as cv
from cvzone.HandTrackingModule import HandDetector
class Button:
def __init__(self, pos, width, height, value):
self.pos = pos
self.width = width
self.height = height
self.value = value
def draw(self, frame):
cv.rectangle(frame, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
(225, 255, 225), cv.FILLED)
cv.rectangle(frame, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
(50, 50, 225), 4)
cv.putText(frame, self.value, (self.pos[0] + 20, self.pos[1] + 50),
cv.FONT_HERSHEY_PLAIN, 2, (50, 50, 225), 2)
def clickCheck(self, x, y, frame):
if self.pos[0] < x < self.pos[0] + self.width and self.pos[1] < y < self.pos[1] + self.height:
cv.rectangle(frame, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
(255, 255, 225), cv.FILLED)
cv.rectangle(frame, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
(0, 0, 50), 4)
cv.putText(frame, self.value, (self.pos[0] + 20, self.pos[1] + 50),
cv.FONT_HERSHEY_PLAIN, 2, (50, 50, 25), 6)
return True
return False
detect = HandDetector(detectionCon=0.9, maxHands=1)
butListVal = [
['1', '2', '3', '+'],
['4', '5', '6', '-'],
['7', '8', '9', '*'],
['0', '/', '.', '=']
]
butList = [Button((x * 100 + 800, y * 100 + 150), 100, 100, butListVal[y][x]) for x in range(4) for y in range(4)]
myEq = ""
delayCounter = 0
finEq = ""
def serve(frame):
global myEq, delayCounter, finEq
frame = cv.flip(frame, 1)
hand, frame = detect.findHands(frame, flipType=False)
cv.rectangle(frame, (800, 50), (1200, 150), (225, 255, 225), cv.FILLED)
cv.rectangle(frame, (800, 50), (1200, 150), (50, 50, 225), 4)
for button in butList:
button.draw(frame)
ev=""
if hand:
lmList = hand[0]['lmList']
length, info, frame = detect.findDistance(lmList[8][:2], lmList[12][:2], frame)
x, y = lmList[8][:2]
if length < 35:
for i, button in enumerate(butList):
if button.clickCheck(x, y, frame) and delayCounter == 0:
myVal = butListVal[int(i % 4)][int(i / 4)]
if myVal == '=' and myEq != "":
finEq = str(eval(myEq))
ev=myEq+"="+finEq
myEq = ""
elif myVal != '=':
myEq += myVal
finEq = ""
delayCounter = 1
if delayCounter != 0:
delayCounter += 1
if delayCounter > 10:
delayCounter = 0
display_text = finEq if myEq == "" else myEq
cv.putText(frame, display_text, (820, 114), cv.FONT_HERSHEY_PLAIN, 3, (50, 50, 225), 3)
if ev!="":
return frame,ev
else:
return frame,""
================================================
FILE: requirements.txt
================================================
absl-py==2.1.0
attrs==23.2.0
blinker==1.8.2
cffi==1.16.0
click==8.1.7
colorama==0.4.6
contourpy==1.2.1
cvzone==1.6.1
cycler==0.12.1
Flask==3.0.3
Flask-Cors==4.0.1
flatbuffers==24.3.25
fonttools==4.53.0
gunicorn==22.0.0
importlib_metadata==8.0.0
importlib_resources==6.4.0
itsdangerous==2.2.0
jax==0.4.30
jaxlib==0.4.30
Jinja2==3.1.4
kiwisolver==1.4.5
MarkupSafe==2.1.5
matplotlib==3.9.1
mediapipe==0.10.14
ml-dtypes==0.4.0
numpy==2.0.0
opencv-contrib-python==4.10.0.84
opencv-python==4.10.0.84
opt-einsum==3.3.0
packaging==24.1
pillow==10.4.0
protobuf==4.25.3
pycparser==2.22
pyparsing==3.1.2
python-dateutil==2.9.0.post0
scipy==1.13.1
six==1.16.0
sounddevice==0.4.7
Werkzeug==3.0.3
zipp==3.19.2
================================================
FILE: static/serve.js
================================================
const processedVideo = document.getElementById('processed-video');
// Request access to the camera
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
const videoTracks = stream.getVideoTracks();
const track = videoTracks[0];
const imageCapture = new ImageCapture(track);
processFrames(imageCapture);
})
.catch(error => {
console.error('Error accessing the camera: ', error);
});
function processFrames(imageCapture) {
const fps = 10; // Frames per second
setInterval(() => {
imageCapture.grabFrame()
.then(imageBitmap => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 1280;
canvas.height = 900;
context.drawImage(imageBitmap, 0, 0, canvas.width, canvas.height);
canvas.toBlob(blob => {
const formData = new FormData();
formData.append('frame', blob, 'frame.jpg');
fetch('/process_frame', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Display the processed frame
processedVideo.src = 'data:image/jpeg;base64,' + data.frame;
} else {
console.error('Error processing frame: ', data.message);
}
})
.catch(error => {
console.error('Error processing frame: ', error);
});
}, 'image/jpeg');
})
.catch(error => {
console.error('Error grabbing frame: ', error);
});
}, 1000 / fps);
}
function updateHisory(){
fetch('/get_history').then(response => response.json()).then(data => {
if (data.success) {
const historyList = document.getElementById('history-list');
console.log(data.history);
historyList.innerHTML = '';
data.history.forEach(item => {
const listItem = document.createElement('li');
listItem.textContent = item;
historyList.appendChild(listItem);
});
} else {
console.error('Error getting history: ', data.message);
}
}).catch(error => {
console.error('Error getting history: ', error);
});
}
setInterval(updateHisory, 2000);
================================================
FILE: templates/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body class="bg-dark text-light">
<header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom mx-5 px-5 rounded ">
<div class="col-md-3 mb-2 mb-md-0">
<a href="/" class="d-inline-flex link-body-emphasis text-decoration-none">
<svg class="bi" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg>
</a>
</div>
<div class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
<h3 style="font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif " ><strong> Virtual Calculator </strong></h3>
</div>
<div class="col-md-3 text-end d-flex align-items-center justify-content-around">
<p style="font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; margin: 0;">Connect with me:</p>
<div class="d-flex gap-2">
<a href="https://www.linkedin.com/in/hazsyl1/">
<button type="button" class="btn btn-primary">LinkedIn</button>
</a>
<a href="https://github.com/HazSyl1">
<button type="button" class="btn btn-primary">GitHub</button>
</a>
</div>
</header>
<main style="display: flex;flex-direction: column; justify-content: center; align-items: center; height: 100%; ">
<!-- <img style="display: block;" src="{{url_for('video_function')}}" alt="Video Footage" width="50%" height="auto"> -->
<!-- <video style="border:2px solid #333; border-radius: 8px; margin:10px;" id="video" autoplay></video> -->
<img id="processed-video" alt="Processed Frame" width="50%" height="auto">
<script src="{{ url_for('static',filename='serve.js') }}"></script>
<p style="font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; margin: 0;">Refresh to restart!</p>
<div style="margin-top: 20px;">
<ul id="history-list" style="list-style: none; padding-left: 0;">
{% for item in history %}
<li style="font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; margin: 0;">{{item}}</li>
{% endfor %}
</ul>
</div>
</main>
</body>
</html>
gitextract_mpzxbp6l/
├── .gitignore
├── Dockerfile
├── README.md
├── app.py
├── main.py
├── requirements.txt
├── static/
│ └── serve.js
└── templates/
└── index.html
SYMBOL INDEX (11 symbols across 3 files)
FILE: app.py
function process_frame (line 46) | def process_frame():
function update_history (line 68) | def update_history():
function index (line 74) | def index():
function video_function (line 80) | def video_function():
FILE: main.py
class Button (line 4) | class Button:
method __init__ (line 5) | def __init__(self, pos, width, height, value):
method draw (line 11) | def draw(self, frame):
method clickCheck (line 19) | def clickCheck(self, x, y, frame):
function serve (line 46) | def serve(frame):
FILE: static/serve.js
function processFrames (line 17) | function processFrames(imageCapture) {
function updateHisory (line 54) | function updateHisory(){
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (13K chars).
[
{
"path": ".gitignore",
"chars": 9,
"preview": "/virtualC"
},
{
"path": "Dockerfile",
"chars": 367,
"preview": "FROM python:3.9-slim \n\nWORKDIR /\nCOPY . .\nRUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y\nRUN apt-get u"
},
{
"path": "README.md",
"chars": 91,
"preview": "A virtual calculator build using OpenCV.\nDEMO: https://www.youtube.com/watch?v=M8ZjUq8QD10\n"
},
{
"path": "app.py",
"chars": 2055,
"preview": "from flask import Flask,render_template,Response, jsonify , request\nimport cv2 as cv \nfrom main import serve\nimport nump"
},
{
"path": "main.py",
"chars": 3102,
"preview": "import cv2 as cv\r\nfrom cvzone.HandTrackingModule import HandDetector\r\n\r\nclass Button:\r\n def __init__(self, pos, width"
},
{
"path": "requirements.txt",
"chars": 696,
"preview": "absl-py==2.1.0\nattrs==23.2.0\nblinker==1.8.2\ncffi==1.16.0\nclick==8.1.7\ncolorama==0.4.6\ncontourpy==1.2.1\ncvzone==1.6.1\ncyc"
},
{
"path": "static/serve.js",
"chars": 2709,
"preview": "const processedVideo = document.getElementById('processed-video');\n\n// Request access to the camera\nnavigator.mediaDevic"
},
{
"path": "templates/index.html",
"chars": 3031,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE="
}
]
About this extraction
This page contains the full source code of the HazSyl1/Virtual_Calculator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (11.8 KB), approximately 3.4k tokens, and a symbol index with 11 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.