Projects

NumArt

Github Repository

Overview: NumArt is an end-to-end system that transforms a user’s uploaded image into a printable paint-by-numbers kit and, optionally, dispenses the required paint colors using a hardware mixer. The software pipeline handles color quantization, segmentation, and vectorization to produce a clean, scalable SVG output, while the hardware setup uses Raspberry Pi–controlled peristaltic pumps to mix and dispense paint according to the generated palette. The project combines computer vision, clustering algorithms, and embedded systems for a full digital-to-physical creative workflow.

A demo of the NumArt project, showing a photo of a dog after running the NumArt software on it.

Key Features:

  • Image Quantization: Uses K-Means clustering (via scikit-learn) to reduce an input image to k representative colors. Each pixel is assigned to the nearest cluster centroid, creating a simplified color palette ideal for painting.
  • Label Map Generation: The quantized image is converted into a 2D label map, where each pixel corresponds to its color index. This map is cleaned using majority filters and region-merging algorithms to remove noise and ensure paintable areas.
  • Vectorization & SVG Export: The cleaned label map is converted into vector paths, with each region assigned a number and lightly filled for visibility. The final SVG includes a color legend and can be printed directly as a paint-by-numbers template.
  • Hardware Integration: A Raspberry Pi 4 controls five 12V peristaltic pumps connected to color reservoirs (Red, Green, Blue, White, Black). The pumps precisely dispense paint volumes to recreate the digital palette physically.
  • Python Driver & FastAPI Backend: A Python FastAPI service coordinates the process—from receiving an image upload to processing it through the quantization pipeline and sending dosing instructions to the Pi for paint mixing. The Modbus or GPIO driver handles real-time pump control and calibration.
  • Physical Assembly: Pumps are mounted in an enclosure and connected via silicone tubing to color reservoirs and a magnetic stirrer. The Raspberry Pi, relay board, and 12V PSU are wired with shared ground and secured for safety and reliability.

Technology Used: Python 3.12, FastAPI, NumPy, Pillow, scikit-learn (K-Means), OpenCV, svgwrite, Raspberry Pi 4, peristaltic pumps, relay modules, and 12V DC power electronics.

Process: The project begins with image validation and downsizing before applying K-Means to extract dominant colors. The palette and label map are refined with region cleanup and distance transforms to ensure each zone is large enough to paint. The resulting vector outlines are exported as a numbered SVG. In parallel, the Raspberry Pi interprets the same palette and activates each pump for a calibrated duration to produce corresponding paint mixtures in small beakers with magnetic stirrers. The system can handle up to five base colors and generate custom blends automatically.

Challenges: Achieving clean segmentation for complex images, balancing speed versus accuracy in K-Means clustering, preventing color bleeding between small regions, and synchronizing hardware control for consistent dosing were key engineering hurdles. Additionally, ensuring repeatable pump calibration and stable power distribution on the Pi relay circuit required careful tuning and testing.

RISC Processor

Github Repository

Overview: This project involved the design and implementation of a custom RISC-style processor with 8 general-purpose registers and a compact instruction set architecture. The goal was to build a minimal yet functional CPU capable of executing arithmetic, logic, and branch instructions, including support for 16-bit integer and 16-bit IEEE-754 floating-point data conversions and addition/subtraction. We used the processor's custom instruction set to write a program in Assembly Language to handle the conversion and computations. A custom compiler for the instruction set, to convert the program from ASM to machine code was also created using C++.

Key Features:

  • Register-register / Load-store architecture with direct and indirect addressing
  • Optimized register file design, prioritizing registers 0 to 3 for frequently accessed operations, while 4 to 7 are utilized for storage. Special handling of 0 as the implied destination for certain branch comparisons.
  • LUT-based conditional branching and control flow, storing up to 32 jump locations
  • Custom instructions for logical shifts, bit manipulation, and subroutine handling
  • Logical shifts can span one or two registers.
  • Support for 16-bit integer and 16-bit IEEE-754 floating-point data types
  • 8-bit wide, 256-byte deep memory, to support indirect addressing during memory access instructions
  • The ALU also supports a comparison operation. Given two registers (R0 and R1), it will compare the data in these registers and return one of three values..
  • Control unit to decode the instruction code (op-code) and manage the flow of data across the data path.

Technology Used: Verilog, SystemVerilog, C++, ModelSim, waveform analysis tools, Assembly Language(ASM)

Process: The processor architecture was designed from the ground up, starting with the instruction set and register file. An ALU module was built to support both standard arithmetic and custom bitwise operations. A memory subsystem handled instruction and data memory independently. Testing was performed with custom testbenches and waveform outputs to validate correctness at each stage.

Challenges: Addressing edge cases in floating-point conversion, handling operand ordering in memory instructions, and eliminating infinite loop scenarios in early branch logic prototypes.

Instruction Set Overview:

Instruction Type Description Bit Breakdown
and R Logical AND between two registers 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0000
or R Logical OR between two registers 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0001
lsl R Logical shift left 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0010
lsr R Logical shift right 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0011
add R Add two registers 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0100
sub R Subtract one register from another 8: branch (0), 7–6: src, 5–4: dest, 3–0: 1101
neg R Negate register value 8: branch (0), 7–6: src, 5–4: dest, 3–0: 0101
ldr R Load value from memory 8: branch (0), 7–6: addr, 5–4: dest, 3–0: 0110
str R Store register to memory 8: branch (0), 7–6: src, 5–4: addr, 3–0: 0111
mov R Move immediate to register 8: branch (0), 7–4: value, 3–0: 1000
mot R Move to/from R0 8: branch (0), 7–5: reg, 4: direction, 3–0: 1001
lso R 1-bit logical shift 8: branch (0), 7–5: reg, 4: L/R, 3–0: 1010
cfb R Check first bit 8: branch (0), 7–5: reg, 4: dead, 3–0: 1011
cmp R Compare registers 8: branch (0), 7–6: dest, 5–4: src, 3–0: 1100
mbs R Move bits 8: branch (0), 7–5: reg, 4: bit count, 3–0: 1110
beq B Branch if equal 8: branch (1), 7–6: reg, 5: 0, 4–0: LUT index
bne B Branch if not equal 8: branch (1), 7–6: reg, 5: 1, 4–0: LUT index

PokeCollect

GitHub Repository

Overview: PokéCollect is a full-stack, component-based web application that enables users to browse, collect, and organize Pokémon cards from all generations. Designed for TCG collectors, the app supports real-time data integration, responsive UI, and persistent offline access using progressive web app (PWA) features.

A demonstration of the PokeCollect app showing card search and collection features.

Key Features:

  • Dynamic card search and retrieval with high-quality metadata (HP, rarity, set, pricing)
  • Stateful collection management and binder customization by clicking to assign cards to specific slots
  • Service workers and API fallback for robust offline functionality
  • Modular design with reusable Web Components and clean separation of concerns
  • Fully integrated CI/CD pipeline with GitHub Actions for build, test, and deployment automation
  • Unit testing (Jest), static analysis (Codacy), linting (ESLint), and >70% code coverage enforcement

Technology Stack: HTML5, CSS3, JavaScript (ES6+), Web Components, GitHub Actions, Jest, ESLint, Codacy, Service Workers, Pokémon TCG API

Development Process: Followed Agile methodologies with sprint planning, issue tracking, code reviews, and iterative delivery through GitHub Projects and pull requests.

Challenges: Managing state across dynamic components, ensuring consistent data synchronization between frontend and API layers, and maintaining high code quality through continuous integration workflows.

Accomplishments: Deployed a production-ready, mobile-responsive web application with a scalable architecture, developer-friendly tooling, and seamless user experience tailored to the TCG community.