# Project export: Banana Fit

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Live counter of the amount of traffic straight from the UC Santa Cruz Opers Gym. Able to determine crowd trends, capacity, as well as the best times to go get a workout in!
- Devpost: https://devpost.com/software/banana-fit
- GitHub: https://github.com/Cruz-Hacks-Demo-ATALLDAB/Cruz-Hacks-Demo-ATALLDAB.github.io
- Team: 3 GitHub contributor(s) — Akshat Tiwari (20 commits), ascliu123 (5 commits), Cruz-Hacks-Demo-ATALLDAB (4 commits)

## Devpost submission (written by the team)

### Overview

Learned HTML, JavaScript, CSS in order to try and create a live counter of how many people there is at the UCSC gym. Currently in the works of communicating with Santa Cruz gym officials in order to develop live crowd tracking. Students at UCSC don’t know the optimal hours to actually go the gym, with a singular gym on campus can’t sustain hundreds of students. This causes workouts to take much longer than they should at times and also can be a health hazard with a large number of people in an enclosed area. Lines go through the door, preventing people from getting their full workouts in! Our solution to this is a website, BananaFit, that displays the current occupancy of the gym. BananaFit has the current time, counter of people at the gym, and percentage capacity that it is full. Additionally, it uses historical data in order to determine how many people are at the gym right now (until LIVE data is received from UCSC). We also plan to implement Object Detection (prototype available) in order to determine if people leave the gym in an automated way. Our First Hackathon so we gained a lot of experience! BananaFit

## README (from the GitHub repository)

# Cruz-Hacks-Demo-ATALLDAB.github.io

run python3 app.py in same directory as provided video to see pedestrian recognition in action


## Detected evidence (automated analysis)

Indexed codebase: 4 recognized source files, 31 KB.
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- CSS (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (4 of 4)

```
app.py
index.html
mail.js
README.md
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- new closed hours
- closed things
- Update index.html
- Add files via upload
- Update README.md
- Update app.py
- Delete vid2.mp4
- Update README.md
- Add files via upload
- Update index.html with bootstrap
- Update index.html
- Update index.html
- Update mail.js
- pp
- Fully updated
- Update index.html
- pusuhhhhhh
- Update index.html
- Create style.css
- Update index.html

## Key source files (fetched from GitHub, selected and truncated for size)

### app.py

```python
import cv2
import imutils
import time

# Initialize background subtractor
bg_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()

# Initialize HOG descriptor for person detection
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

# Source example video
cap = cv2.VideoCapture('1.mov')

# Counters for detected persons during motion and total persons
person_counter = 0
total_people_count = 0
motion_detected = False
counted_during_motion = False
start_time = 0
delay_time = 4  # 1 second delay before checking the number of persons
motion_stopped = True
motion_pause_time = 0.2 # Maximum duration of a pause to be considered part of the same motion event

while cap.isOpened():
    # Read in video
    ret, frame = cap.read()
    if ret:
        frame = imutils.resize(frame, width=min(400, frame.shape[1]))

        # Apply background subtraction
        fg_mask = bg_subtractor.apply(frame)

        # Threshold the foreground mask
        _, thresh = cv2.threshold(fg_mask, 25, 255, cv2.THRESH_BINARY)

        # Find contours in the thresholded mask
        contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        # Check if motion is detected
        if len(contours) > 0:
            if not motion_detected:
                # Motion has started, reset flags and start timer
                motion_detected = True
                counted_during_motion = False
                start_time = time.time()
                motion_stopped = False
        else:
            if motion_detected and not motion_stopped:
                # Motion has stopped, check if the pause is within the defined limit
                elapsed_time = time.time() - start_time
                if elapsed_time >= motion_pause_time:
                    # Pause is beyond the limit, reset flags and increment total people count
                    motion_stopped = True
                    counted_during_motion = False
                    total_people_count += person_counter
                    person_counter = 0

        # If motion is detected and not counted during the current motion event
        if motion_detected and not counted_during_motion:
            # Check if 1 second has passed since motion began
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay_time:
                # Detecting all the regions
                (regions, _) = hog.detectMultiScale(frame, winStride=(4, 4), padding=(4, 4), scale=1.05)

                # Drawing rectangles on persons
                for (x, y, w, h) in regions:
                    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

                # Increment person counter
                person_counter += len(regions)
                total_people_count += len(regions)
                counted_during_motion = True

        # Display video output
        cv2.putText(frame, f'Persons during motion: {person_counter}', (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        cv2.putText(frame, f'Total People Counted: {total_people_count}', (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        cv2.imshow("Motion Detection", frame)

        if cv2.waitKey(25) & 0xFF == ord('q'):
            break
    else:
        break

# Clean up
cap.release()
cv2.destroyAllWindows()

```

### mail.js

```javascript
const firebaseConfig = {
    apiKey: "AIzaSyCymdaMs4v-T6I17vXtqOEWkoa7gZGBcH0",
    authDomain: "cruzhacks-c022a.firebaseapp.com",
    databaseURL: "https://cruzhacks-c022a-default-rtdb.firebaseio.com",
    projectId: "cruzhacks-c022a",
    storageBucket: "cruzhacks-c022a.appspot.com",
    messagingSenderId: "548963977111",
    appId: "1:548963977111:web:c40314b14896b7708826d2",
    measurementId: "G-4RTYT6C79B"
};

firebase.initializeApp(firebaseConfig);
var contactFormDB = firebase.database().ref('contactForm');

// Add event listener for the "out" button
document.getElementById('outButton').addEventListener('click', saveAndPrintCount);

function saveAndPrintCount() {
   var currentPeopleCount = getElementVal('current-people-count');

   // Save the current people count to the database
   contactFormDB.push().set({
       currentPeopleCount: currentPeopleCount,
       timestamp: firebase.database.ServerValue.TIMESTAMP
   });

   // Print the current people count
   console.log('Current people count:', currentPeopleCount);
}

const getElementVal = (id) => {
   return document.getElementById(id).value;
};
```

### index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="icon" href="bananastill.jpg" type="image/jpg">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
    <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@700&display=swap" rel="stylesheet">

    <title>BananaFit</title>
<style>
  body {
    min-height: 100vh;
    background: radial-gradient(ellipse at bottom, #0d1d31 0%, #0c0d13 100%);
    overflow: hidden;
    color: #fdc700;
    font-family: 'Work Sans';
    font-weight: bolder;
}

.stars {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 120%;
  transform: rotate(-45deg);
}

.star {
    --star-color: #fdc700;
  --star-tail-length: 6em;
  --star-tail-height: 2px;
  --star-width: calc(var(--star-tail-length) / 6);
  --fall-duration: 9s;
  --tail-fade-duration: var(--fall-duration);
  position: absolute;
  top: var(--top-offset);
  left: 0;
  width: var(--star-tail-length);
  height: var(--star-tail-height);
  color: var(--star-color);
  background: linear-gradient(45deg, currentColor, transparent);
  border-radius: 50%;
  filter: drop-shadow(0 0 6px currentColor);
  transform: translate3d(104em, 0, 0);
  animation: fall var(--fall-duration) var(--fall-delay) linear infinite, tail-fade var(--tail-fade-duration) var(--fall-delay) ease-out infinite;
}
@media screen and (max-width: 750px) {
  .star {
    animation: fall var(--fall-duration) var(--fall-delay) linear infinite;
  }
}
.star:nth-child(1) {
  --star-tail-length: 6.4em;
  --top-offset: 84.07vh;
  --fall-duration: 9.524s;
  --fall-delay: 7.676s;
}
.star:nth-child(2) {
  --star-tail-length: 6.92em;
  --top-offset: 77.65vh;
  --fall-duration: 8.906s;
  --fall-delay: 3.141s;
}
.star:nth-child(3) {
  --star-tail-length: 5.19em;
  --top-offset: 17.65vh;
  --fall-duration: 10.482s;
  --fall-delay: 6.575s;
}
.star:nth-child(4) {
  --star-tail-length: 6.61em;
  --top-offset: 62.27vh;
  --fall-duration: 11.404s;
  --fall-delay: 4.895s;
}
.star:nth-child(5) {
  --star-tail-length: 5.37em;
  --top-offset: 68.31vh;
  --fall-duration: 6.52s;
  --fall-delay: 9.05s;
}
.star:nth-child(6) {
  --star-tail-length: 6.53em;
  --top-offset: 34.46vh;
  --fall-duration: 9.659s;
  --fall-delay: 1.187s;
}
.star:nth-child(7) {
  --star-tail-length: 6.47em;
  --top-offset: 10.63vh;
  --fall-duration: 8.445s;
  --fall-delay: 9.899s;
}
.star:nth-child(8) {
  --star-tail-length: 5.95em;
  --top-offset: 91.85vh;
  --fall-duration: 7.287s;
  --fall-delay: 4.14s;
}
.star:nth-child(9) {
  --star-tail-length: 6.8em;
  --top-offset: 5.89vh;
  --fall-duration: 6.548s;
  --fall-delay: 7.142s;
}
.star:nth-child(10) {
  --star-tail-length: 5.15em;
  --top-offset: 78.1vh;
  --fall-duration: 7.992s;
  --fall-delay: 1.912s;
}
.star:nth-child(11) {
  --star-tail-length: 7.19em;
  --top-offset: 96.16vh;
  --fall-duration: 9.391s;
  --fall-delay: 7.343s;
}
.star:nth-child(12) {
  --star-tail-length: 5.14em;
  --top-offset: 73.58vh;
  --fall-duration: 9.32s;
  --fall-delay: 5.17s;
}
.star:nth-child(13) {
  --star-tail-length: 6.99em;
  --top-offset: 81.27vh;
  --fall-duration: 10.017s;
  --fall-delay: 8.317s;
}
.star:nth-child(14) {
  --star-tail-length: 5em;
  --top-offset: 7.83vh;
  --fall-duration: 10.232s;
  --fall-delay: 1.342s;
}
.star:nth-child(15) {
  --star-tail-length: 7.34em;
  --top-offset: 69.45vh;
  --fall-duration: 9.196s;
  --fall-delay: 4.489s;
}
.star:nth-child(16) {
  --star-tail-length: 5.54em;
  --top-offset: 26.53vh;
  --fall-duration: 11.876s;
  --fall-delay: 2.378s;
}
.star:nth-child(17) {
  --star-tail-length: 5.51em;
  --top-offset: 56.34vh;
  --fall-duration: 8.989s;
  --fall-delay: 6.391s;
}
.star:nth-child(18) {
  --star-tail-length: 7.05em;
  --top-offset: 99.46vh;
  --fall-duration: 6.814s;
  --fall-delay: 6.66s;
}
.star:nth-child(19) {
  --star-tail-length: 5.22em;
  --top-offset: 53.05vh;
  --fall-duration: 11.303s;
  --fall-delay: 8.306s;
}
.star:nth-child(20) {
  --star-tail-length: 5.59em;
  --top-offset: 28.04vh;
  --fall-duration: 11.352s;
  --fall-delay: 4.849s;
}
.star:nth-child(21) {
  --star-tail-length: 5.7em;
  --top-offset: 47.55vh;
  --fall-duration: 9.192s;
  --fall-delay: 0.919s;
}
.star:nth-child(22) {
  --star-tail-length: 7.25em;
  --top-offset: 28.76vh;
  --fall-duration: 10.02s;
  --fall-delay: 5.81s;
}
.star:nth-child(23) {
  --star-tail-length: 6.46em;
  --top-offset: 62.07vh;
  --fall-duration: 7.63s;
  --fall-delay: 7.304s;
}
.star:nth-child(24) {
  --star-tail-length: 5.11em;
  --top-offset: 28.87vh;
  --fall-duration: 11.327s;
  --fall-delay: 8.386s;
}
.star:nth-child(25) {
  --star-tail-length: 6.45em;
  --top-offset: 7.13vh;
  --fall-duration: 8.269s;
  --fall-delay: 3.328s;
}
.star:nth-child(26) {
  --star-tail-length: 6.74em;
  --top-offset: 99.05vh;
  --fall-duration: 11.476s;
  --fall-delay: 4.896s;
}
.star:nth-child(27) {
  --star-tail-length: 6.71em;
  --top-offset: 80.6vh;
  --fall-duration: 8.707s;
  --fall-delay: 7.763s;
}
.star:nth-child(28) {
  --star-tail-length: 6.57em;
  --top-offset: 56.82vh;
  --fall-duration: 8.319s;
  --fall-delay: 8.309s;
}
.star:nth-child(29) {
  --star-tail-length: 6.77em;
  --top-offset: 66.61vh;
  --fall-duration: 8.703s;
  --fall-delay: 0.941s;
}
.star:nth-child(30) {
  --star-tail-length: 6.05em;
  --top-offset: 85.74vh;
  --fall-duration: 9.289s;
  --fall-delay: 5.663s;
}
.star:nth-child(31) {
  --star-tail-length: 6.33em;
  --top-offset: 57.31vh;
  --fall-duration: 7.183s;
  --fall-delay: 8.977s;
}
.star:nth-child(32) {
  --star-tail-length: 5.44em;
  --top-offset: 5.5
[truncated — 21629 more characters]
```