version k-means qui marche!!
2
boonepeter.github.io-code/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
__pycache__
|
||||
.venv
|
||||
@@ -1,12 +0,0 @@
|
||||
# Code snippets
|
||||
|
||||
This repo contains the code snippets I reference in [my blog](https://boonepeter.github.io/).
|
||||
|
||||
## Index
|
||||
|
||||
Code|Blog Post|
|
||||
---|---|
|
||||
[spotify-codes](./spotify-codes)|[How do Spotify Codes Work?](https://boonepeter.github.io/posts/2020-11-10-spotify-codes/)|
|
||||
[spotify-codes-part-2](./spotify-codes-part-2)|[Spotify Codes Part 2](https://boonepeter.github.io/posts/spotify-codes-part-2/)
|
||||
[snapcodes](./snapcodes)|No post yet
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# Snapcodes
|
||||
|
||||
Using Python 3.10.1
|
||||
|
||||
```bash
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
Running this command
|
||||
|
||||
```bash
|
||||
python3 img_to_points.py snapcode.png
|
||||
```
|
||||
|
||||
Gets the points from this image:
|
||||
|
||||

|
||||
|
||||
Points:
|
||||
|
||||
```python
|
||||
[1, 2, 3, 4, 6, 9, 14, 18, 20, 21, 22, 23, 27, 28, 29, 30, 32, 38, 39, 41, 43, 44, 45, 49, 53, 58, 59, 62, 64, 65, 66, 67, 70, 71, 73, 76, 77, 83, 87, 90, 93, 94, 96, 99, 100, 101, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 115, 118, 119, 120, 130, 131, 134, 140, 141, 144, 145, 146, 150, 153, 155, 157, 159, 161, 163, 169, 170, 171, 172, 173, 174, 175, 178, 182, 183, 184, 185, 188, 190, 192, 193, 196, 197, 202, 204, 206, 207, 209]
|
||||
```
|
||||
|
||||
Points are numbered left to right, top to bottom, starting with 0 and ending at 211.
|
||||
|
||||
And this command
|
||||
|
||||
```bash
|
||||
python3 img_to_svg.py -i snapcode.png -o output.svg
|
||||
```
|
||||
|
||||
Outputs an SVG file:
|
||||
|
||||

|
||||
|
||||
The svg is useful for checking that the point parsing was correct.
|
||||
@@ -1,10 +0,0 @@
|
||||
imageio==2.13.5
|
||||
networkx==2.6.3
|
||||
numpy==1.22.1
|
||||
packaging==21.3
|
||||
Pillow==9.0.0
|
||||
pyparsing==3.0.6
|
||||
PyWavelets==1.2.0
|
||||
scikit-image==0.19.1
|
||||
scipy==1.7.3
|
||||
tifffile==2021.11.2
|
||||
@@ -1,2 +0,0 @@
|
||||
/imgs
|
||||
.ipynb_checkpoints/
|
||||
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 119 KiB |
@@ -1,305 +0,0 @@
|
||||
import argparse
|
||||
from skimage import io
|
||||
import numpy as np
|
||||
from skimage import io, img_as_ubyte
|
||||
from skimage.filters import threshold_otsu
|
||||
from skimage.color import rgb2gray, rgba2rgb
|
||||
from skimage.measure import label, regionprops
|
||||
|
||||
## BBOX of points from all_dots_yellow.png
|
||||
ALL_BBOX = [
|
||||
[0.025, 0.076, 0.0583, 0.1094],
|
||||
[0.025, 0.1271, 0.0583, 0.1604],
|
||||
[0.025, 0.1781, 0.0583, 0.2115],
|
||||
[0.025, 0.2292, 0.0583, 0.2625],
|
||||
[0.025, 0.2802, 0.0583, 0.3135],
|
||||
[0.025, 0.3302, 0.0583, 0.3635],
|
||||
[0.025, 0.3812, 0.0583, 0.4146],
|
||||
[0.025, 0.4323, 0.0583, 0.4656],
|
||||
[0.025, 0.4833, 0.0583, 0.5167],
|
||||
[0.025, 0.5344, 0.0583, 0.5677],
|
||||
[0.025, 0.5854, 0.0583, 0.6188],
|
||||
[0.025, 0.6365, 0.0583, 0.6698],
|
||||
[0.025, 0.6865, 0.0583, 0.7198],
|
||||
[0.025, 0.7375, 0.0583, 0.7708],
|
||||
[0.025, 0.7885, 0.0583, 0.8219],
|
||||
[0.025, 0.8396, 0.0583, 0.8729],
|
||||
[0.025, 0.8906, 0.0583, 0.924],
|
||||
[0.076, 0.025, 0.1094, 0.0583],
|
||||
[0.076, 0.076, 0.1094, 0.1094],
|
||||
[0.076, 0.1271, 0.1094, 0.1604],
|
||||
[0.076, 0.1781, 0.1094, 0.2115],
|
||||
[0.076, 0.2292, 0.1094, 0.2625],
|
||||
[0.076, 0.2802, 0.1094, 0.3135],
|
||||
[0.076, 0.3302, 0.1094, 0.3635],
|
||||
[0.076, 0.3812, 0.1094, 0.4146],
|
||||
[0.076, 0.4323, 0.1094, 0.4656],
|
||||
[0.076, 0.4833, 0.1094, 0.5167],
|
||||
[0.076, 0.5344, 0.1094, 0.5677],
|
||||
[0.076, 0.5854, 0.1094, 0.6188],
|
||||
[0.076, 0.6365, 0.1094, 0.6698],
|
||||
[0.076, 0.6865, 0.1094, 0.7198],
|
||||
[0.076, 0.7375, 0.1094, 0.7708],
|
||||
[0.076, 0.7885, 0.1094, 0.8219],
|
||||
[0.076, 0.8396, 0.1094, 0.8729],
|
||||
[0.076, 0.8906, 0.1094, 0.924],
|
||||
[0.076, 0.9417, 0.1094, 0.975],
|
||||
[0.1271, 0.025, 0.1604, 0.0583],
|
||||
[0.1271, 0.076, 0.1604, 0.1094],
|
||||
[0.1271, 0.1271, 0.1604, 0.1604],
|
||||
[0.1271, 0.1781, 0.1604, 0.2115],
|
||||
[0.1271, 0.2292, 0.1604, 0.2625],
|
||||
[0.1271, 0.2802, 0.1604, 0.3135],
|
||||
[0.1271, 0.3312, 0.1604, 0.3635],
|
||||
[0.1271, 0.3812, 0.1604, 0.4146],
|
||||
[0.1271, 0.4323, 0.1604, 0.4656],
|
||||
[0.1271, 0.4833, 0.1604, 0.5167],
|
||||
[0.1271, 0.5344, 0.1604, 0.5677],
|
||||
[0.1271, 0.5854, 0.1604, 0.6188],
|
||||
[0.1271, 0.6365, 0.1604, 0.6698],
|
||||
[0.1271, 0.6865, 0.1604, 0.7198],
|
||||
[0.1271, 0.7375, 0.1604, 0.7708],
|
||||
[0.1271, 0.7885, 0.1604, 0.8219],
|
||||
[0.1271, 0.8396, 0.1604, 0.8729],
|
||||
[0.1271, 0.8906, 0.1604, 0.924],
|
||||
[0.1271, 0.9417, 0.1604, 0.975],
|
||||
[0.1781, 0.025, 0.2115, 0.0583],
|
||||
[0.1781, 0.076, 0.2115, 0.1094],
|
||||
[0.1781, 0.1271, 0.2115, 0.1604],
|
||||
[0.1781, 0.1781, 0.2115, 0.2115],
|
||||
[0.1781, 0.2292, 0.2115, 0.2625],
|
||||
[0.1781, 0.2802, 0.2115, 0.3135],
|
||||
[0.1781, 0.6865, 0.2115, 0.7198],
|
||||
[0.1781, 0.7375, 0.2115, 0.7708],
|
||||
[0.1781, 0.7885, 0.2115, 0.8219],
|
||||
[0.1781, 0.8396, 0.2115, 0.8729],
|
||||
[0.1781, 0.8906, 0.2115, 0.924],
|
||||
[0.1781, 0.9417, 0.2115, 0.975],
|
||||
[0.2292, 0.025, 0.2625, 0.0583],
|
||||
[0.2292, 0.076, 0.2625, 0.1094],
|
||||
[0.2292, 0.1271, 0.2625, 0.1604],
|
||||
[0.2292, 0.1781, 0.2625, 0.2115],
|
||||
[0.2292, 0.2292, 0.2625, 0.2625],
|
||||
[0.2292, 0.7375, 0.2625, 0.7708],
|
||||
[0.2292, 0.7885, 0.2625, 0.8219],
|
||||
[0.2292, 0.8396, 0.2625, 0.8729],
|
||||
[0.2292, 0.8906, 0.2625, 0.924],
|
||||
[0.2292, 0.9417, 0.2625, 0.975],
|
||||
[0.2802, 0.025, 0.3135, 0.0583],
|
||||
[0.2802, 0.076, 0.3135, 0.1094],
|
||||
[0.2802, 0.1271, 0.3135, 0.1604],
|
||||
[0.2802, 0.1781, 0.3135, 0.2115],
|
||||
[0.2802, 0.7885, 0.3135, 0.8219],
|
||||
[0.2802, 0.8396, 0.3135, 0.8729],
|
||||
[0.2802, 0.8906, 0.3135, 0.924],
|
||||
[0.2802, 0.9417, 0.3135, 0.975],
|
||||
[0.3302, 0.025, 0.3635, 0.0583],
|
||||
[0.3302, 0.076, 0.3635, 0.1094],
|
||||
[0.3302, 0.1271, 0.3635, 0.1604],
|
||||
[0.3302, 0.8396, 0.3635, 0.8729],
|
||||
[0.3302, 0.8906, 0.3635, 0.924],
|
||||
[0.3302, 0.9417, 0.3635, 0.975],
|
||||
[0.3812, 0.025, 0.4146, 0.0583],
|
||||
[0.3812, 0.076, 0.4146, 0.1094],
|
||||
[0.3812, 0.1271, 0.4146, 0.1604],
|
||||
[0.3812, 0.8396, 0.4146, 0.8729],
|
||||
[0.3812, 0.8906, 0.4146, 0.924],
|
||||
[0.3812, 0.9417, 0.4146, 0.975],
|
||||
[0.4323, 0.025, 0.4656, 0.0583],
|
||||
[0.4323, 0.076, 0.4656, 0.1094],
|
||||
[0.4323, 0.1271, 0.4656, 0.1604],
|
||||
[0.4323, 0.8396, 0.4656, 0.8729],
|
||||
[0.4323, 0.8906, 0.4656, 0.924],
|
||||
[0.4323, 0.9417, 0.4656, 0.975],
|
||||
[0.4833, 0.025, 0.5167, 0.0583],
|
||||
[0.4833, 0.076, 0.5167, 0.1094],
|
||||
[0.4833, 0.1271, 0.5167, 0.1604],
|
||||
[0.4833, 0.8396, 0.5167, 0.8729],
|
||||
[0.4833, 0.8906, 0.5167, 0.924],
|
||||
[0.4833, 0.9417, 0.5167, 0.975],
|
||||
[0.5344, 0.025, 0.5677, 0.0583],
|
||||
[0.5344, 0.076, 0.5677, 0.1094],
|
||||
[0.5344, 0.1271, 0.5677, 0.1604],
|
||||
[0.5344, 0.8396, 0.5677, 0.8729],
|
||||
[0.5344, 0.8906, 0.5677, 0.924],
|
||||
[0.5344, 0.9417, 0.5677, 0.975],
|
||||
[0.5854, 0.025, 0.6188, 0.0583],
|
||||
[0.5854, 0.076, 0.6188, 0.1094],
|
||||
[0.5854, 0.1271, 0.6188, 0.1604],
|
||||
[0.5854, 0.8396, 0.6188, 0.8729],
|
||||
[0.5854, 0.8906, 0.6188, 0.924],
|
||||
[0.5854, 0.9417, 0.6188, 0.975],
|
||||
[0.6365, 0.025, 0.6698, 0.0583],
|
||||
[0.6365, 0.076, 0.6698, 0.1094],
|
||||
[0.6365, 0.1271, 0.6698, 0.1604],
|
||||
[0.6365, 0.8396, 0.6698, 0.8729],
|
||||
[0.6365, 0.8906, 0.6698, 0.924],
|
||||
[0.6365, 0.9417, 0.6698, 0.975],
|
||||
[0.6865, 0.025, 0.7198, 0.0583],
|
||||
[0.6865, 0.076, 0.7198, 0.1094],
|
||||
[0.6865, 0.1271, 0.7198, 0.1604],
|
||||
[0.6865, 0.1781, 0.7198, 0.2115],
|
||||
[0.6865, 0.7885, 0.7198, 0.8219],
|
||||
[0.6865, 0.8396, 0.7198, 0.8729],
|
||||
[0.6865, 0.8906, 0.7198, 0.924],
|
||||
[0.6865, 0.9417, 0.7198, 0.975],
|
||||
[0.7375, 0.025, 0.7708, 0.0583],
|
||||
[0.7375, 0.076, 0.7708, 0.1094],
|
||||
[0.7375, 0.1271, 0.7708, 0.1604],
|
||||
[0.7375, 0.1781, 0.7708, 0.2115],
|
||||
[0.7375, 0.2292, 0.7708, 0.2625],
|
||||
[0.7375, 0.7375, 0.7708, 0.7708],
|
||||
[0.7375, 0.7885, 0.7708, 0.8219],
|
||||
[0.7375, 0.8396, 0.7708, 0.8729],
|
||||
[0.7375, 0.8906, 0.7708, 0.924],
|
||||
[0.7375, 0.9417, 0.7708, 0.975],
|
||||
[0.7885, 0.025, 0.8219, 0.0583],
|
||||
[0.7885, 0.076, 0.8219, 0.1094],
|
||||
[0.7885, 0.1271, 0.8219, 0.1604],
|
||||
[0.7885, 0.1781, 0.8219, 0.2115],
|
||||
[0.7885, 0.2292, 0.8219, 0.2625],
|
||||
[0.7885, 0.2802, 0.8219, 0.3135],
|
||||
[0.7885, 0.6865, 0.8219, 0.7198],
|
||||
[0.7885, 0.7375, 0.8219, 0.7708],
|
||||
[0.7885, 0.7885, 0.8219, 0.8219],
|
||||
[0.7885, 0.8396, 0.8219, 0.8729],
|
||||
[0.7885, 0.8906, 0.8219, 0.924],
|
||||
[0.7885, 0.9417, 0.8219, 0.975],
|
||||
[0.8396, 0.025, 0.8729, 0.0583],
|
||||
[0.8396, 0.076, 0.8729, 0.1094],
|
||||
[0.8396, 0.1271, 0.8729, 0.1604],
|
||||
[0.8396, 0.1781, 0.8729, 0.2115],
|
||||
[0.8396, 0.2292, 0.8729, 0.2625],
|
||||
[0.8396, 0.2802, 0.8729, 0.3135],
|
||||
[0.8396, 0.3312, 0.8729, 0.3635],
|
||||
[0.8396, 0.3812, 0.8729, 0.4146],
|
||||
[0.8396, 0.4323, 0.8729, 0.4656],
|
||||
[0.8396, 0.4833, 0.8729, 0.5167],
|
||||
[0.8396, 0.5344, 0.8729, 0.5677],
|
||||
[0.8396, 0.5854, 0.8729, 0.6188],
|
||||
[0.8396, 0.6365, 0.8729, 0.6698],
|
||||
[0.8396, 0.6865, 0.8729, 0.7198],
|
||||
[0.8396, 0.7375, 0.8729, 0.7708],
|
||||
[0.8396, 0.7885, 0.8729, 0.8219],
|
||||
[0.8396, 0.8396, 0.8729, 0.8729],
|
||||
[0.8396, 0.8906, 0.8729, 0.924],
|
||||
[0.8396, 0.9417, 0.8729, 0.975],
|
||||
[0.8906, 0.025, 0.924, 0.0583],
|
||||
[0.8906, 0.076, 0.924, 0.1094],
|
||||
[0.8906, 0.1271, 0.924, 0.1604],
|
||||
[0.8906, 0.1781, 0.924, 0.2115],
|
||||
[0.8906, 0.2292, 0.924, 0.2625],
|
||||
[0.8906, 0.2802, 0.924, 0.3135],
|
||||
[0.8906, 0.3302, 0.924, 0.3635],
|
||||
[0.8906, 0.3812, 0.924, 0.4146],
|
||||
[0.8906, 0.4323, 0.924, 0.4656],
|
||||
[0.8906, 0.4833, 0.924, 0.5167],
|
||||
[0.8906, 0.5344, 0.924, 0.5677],
|
||||
[0.8906, 0.5854, 0.924, 0.6188],
|
||||
[0.8906, 0.6365, 0.924, 0.6698],
|
||||
[0.8906, 0.6865, 0.924, 0.7198],
|
||||
[0.8906, 0.7375, 0.924, 0.7708],
|
||||
[0.8906, 0.7885, 0.924, 0.8219],
|
||||
[0.8906, 0.8396, 0.924, 0.8729],
|
||||
[0.8906, 0.8906, 0.924, 0.924],
|
||||
[0.8906, 0.9417, 0.924, 0.975],
|
||||
[0.9417, 0.076, 0.975, 0.1094],
|
||||
[0.9417, 0.1271, 0.975, 0.1604],
|
||||
[0.9417, 0.1781, 0.975, 0.2115],
|
||||
[0.9417, 0.2292, 0.975, 0.2625],
|
||||
[0.9417, 0.2802, 0.975, 0.3135],
|
||||
[0.9417, 0.3302, 0.975, 0.3635],
|
||||
[0.9417, 0.3812, 0.975, 0.4146],
|
||||
[0.9417, 0.4323, 0.975, 0.4656],
|
||||
[0.9417, 0.4833, 0.975, 0.5167],
|
||||
[0.9417, 0.5344, 0.975, 0.5677],
|
||||
[0.9417, 0.5854, 0.975, 0.6188],
|
||||
[0.9417, 0.6365, 0.975, 0.6698],
|
||||
[0.9417, 0.6865, 0.975, 0.7198],
|
||||
[0.9417, 0.7375, 0.975, 0.7708],
|
||||
[0.9417, 0.7885, 0.975, 0.8219],
|
||||
[0.9417, 0.8396, 0.975, 0.8729],
|
||||
[0.9417, 0.8906, 0.975, 0.924],
|
||||
]
|
||||
|
||||
def color_crop(im, color=[(250, 255), (245, 255), (0, 10)]):
|
||||
"""Crop an image to the min and max occurances of a color range.
|
||||
Accepts an image and list of colors (channels and colors must match).
|
||||
"""
|
||||
assert len(color) == im.shape[-1]
|
||||
binary = np.ones(im.shape[:-1], dtype=bool)
|
||||
for i in range(3):
|
||||
binary &= (im[:,:,i] >= color[i][0]) & (im[:,:,i] <= color[i][1])
|
||||
labeled = label(binary, background=0)
|
||||
rp = regionprops(labeled)
|
||||
bbox = max(rp, key=lambda x: x.bbox_area).bbox
|
||||
return im[bbox[0]:bbox[2], bbox[1]:bbox[3], :]
|
||||
|
||||
def _get_points(image):
|
||||
im = rgb2gray(image)
|
||||
t = threshold_otsu(im)
|
||||
return im > t
|
||||
|
||||
|
||||
def get_bbox_and_centers(im, color=[(250, 255), (245, 255), (0, 10)]):
|
||||
im = color_crop(im, color=color)
|
||||
p = _get_points(im)
|
||||
l = label(p, background=1)
|
||||
rp = regionprops(l)
|
||||
(maxx, maxy) = l.shape
|
||||
max_size = l.shape[0] * l.shape[1] // 500
|
||||
min_size = l.shape[0] * l.shape[1] // 2000
|
||||
|
||||
bbs = []
|
||||
centers = []
|
||||
for props in rp:
|
||||
minr, minc, maxr, maxc = props.bbox
|
||||
if props.bbox_area < max_size and props.bbox_area > min_size:
|
||||
bbs.append((props.bbox[0] / maxx, props.bbox[1] / maxx, props.bbox[2] / maxx, props.bbox[3] / maxx))
|
||||
centers.append(
|
||||
(
|
||||
(((minr / maxy) + (maxr / maxy)) / 2),
|
||||
(((minc / maxx) + (maxc / maxx)) / 2)
|
||||
),
|
||||
)
|
||||
return bbs, centers
|
||||
|
||||
def get_numbers(centers, bbs):
|
||||
points = []
|
||||
for i, b in enumerate(bbs):
|
||||
for x, y in centers:
|
||||
if x > b[0] and x < b[2] and y > b[1] and y < b[3]:
|
||||
points.append(i)
|
||||
return points
|
||||
|
||||
def img_to_points(filepath, check_counts=False):
|
||||
im = io.imread(filepath)
|
||||
color = [(250, 255), (245, 255), (0, 10)]
|
||||
# convert to 3 channel
|
||||
if im.shape[-1] == 4:
|
||||
im = rgba2rgb(im)
|
||||
# convert to uint8 (0-255)
|
||||
im = img_as_ubyte(im)
|
||||
try:
|
||||
_, centers = get_bbox_and_centers(im, color)
|
||||
except:
|
||||
try:
|
||||
# for some reason, some of the colors are off
|
||||
# when the images are read in
|
||||
color = [(250, 255), (245, 255), (75, 90)]
|
||||
_, centers = get_bbox_and_centers(im, color)
|
||||
except Exception as e:
|
||||
raise e
|
||||
if check_counts and (len(centers) < 50 or len(centers) > 120):
|
||||
raise Exception("Too many or too few points")
|
||||
return get_numbers(centers, ALL_BBOX)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("filepath", type=str)
|
||||
parser.add_argument("--check_counts", action="store_true")
|
||||
args = parser.parse_args()
|
||||
print(img_to_points(args.filepath, args.check_counts))
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import argparse
|
||||
from img_to_points import img_to_points
|
||||
from points_to_svg import points_to_svg
|
||||
|
||||
def img_to_svg(filepath, output_filepath):
|
||||
"""
|
||||
Converts an image to an SVG file.
|
||||
"""
|
||||
points = img_to_points(filepath, True)
|
||||
print(points)
|
||||
svg = points_to_svg(points)
|
||||
with open(output_filepath, "w") as f:
|
||||
f.write(svg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Convert an image to an SVG file.")
|
||||
parser.add_argument("-i", "--input", help="Input filepath", required=True)
|
||||
parser.add_argument("-o", "--output", help="Output filepath", required=True)
|
||||
args = parser.parse_args()
|
||||
img_to_svg(args.input, args.output)
|
||||
@@ -1,300 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" height="1024" version="1.1" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d=" M749.88,641.75 C763.31,649.46,754.85,644.24,749.88,641.75 M0,860.16 C0,950.64,73.36,1024,163.84,1024 L860.16,1024 C950.64,1024,1024,950.64,1024,860.16 L1024,163.84 C1024,73.36,950.64,0,860.16,0 L163.84,0 C73.36,0,0,73.36,0,163.84 L0,860.16" fill="#000" fill-rule="evenodd"/>
|
||||
<path d="M32,163.84 C32,91.03,91.03,32,163.84,32 L860.16,32 C932.97,32,992,91.03,992,163.84 L992,860.16 C992,932.97,932.97,992,860.16,992 L163.84,992 C91.03,992,32,932.97,32,860.16 L32,163.84
|
||||
M170.10500000000002,56.42
|
||||
A16,16,0,0,0,170.10500000000002,88.42
|
||||
A16,16,0,0,0,170.10500000000002,56.42
|
||||
M218.9475,56.42
|
||||
A16,16,0,0,0,218.9475,88.42
|
||||
A16,16,0,0,0,218.9475,56.42
|
||||
M267.79,56.42
|
||||
A16,16,0,0,0,267.79,88.42
|
||||
A16,16,0,0,0,267.79,56.42
|
||||
M316.6325,56.42
|
||||
A16,16,0,0,0,316.6325,88.42
|
||||
A16,16,0,0,0,316.6325,56.42
|
||||
M414.31750000000005,56.42
|
||||
A16,16,0,0,0,414.31750000000005,88.42
|
||||
A16,16,0,0,0,414.31750000000005,56.42
|
||||
M560.845,56.42
|
||||
A16,16,0,0,0,560.845,88.42
|
||||
A16,16,0,0,0,560.845,56.42
|
||||
M805.0575,56.42
|
||||
A16,16,0,0,0,805.0575,88.42
|
||||
A16,16,0,0,0,805.0575,56.42
|
||||
M121.2625,105.2625
|
||||
A16,16,0,0,0,121.2625,137.2625
|
||||
A16,16,0,0,0,121.2625,105.2625
|
||||
M218.9475,105.2625
|
||||
A16,16,0,0,0,218.9475,137.2625
|
||||
A16,16,0,0,0,218.9475,105.2625
|
||||
M267.79,105.2625
|
||||
A16,16,0,0,0,267.79,137.2625
|
||||
A16,16,0,0,0,267.79,105.2625
|
||||
M316.6325,105.2625
|
||||
A16,16,0,0,0,316.6325,137.2625
|
||||
A16,16,0,0,0,316.6325,105.2625
|
||||
M365.475,105.2625
|
||||
A16,16,0,0,0,365.475,137.2625
|
||||
A16,16,0,0,0,365.475,105.2625
|
||||
M560.845,105.2625
|
||||
A16,16,0,0,0,560.845,137.2625
|
||||
A16,16,0,0,0,560.845,105.2625
|
||||
M609.6875,105.2625
|
||||
A16,16,0,0,0,609.6875,137.2625
|
||||
A16,16,0,0,0,609.6875,105.2625
|
||||
M658.53,105.2625
|
||||
A16,16,0,0,0,658.53,137.2625
|
||||
A16,16,0,0,0,658.53,105.2625
|
||||
M707.3725,105.2625
|
||||
A16,16,0,0,0,707.3725,137.2625
|
||||
A16,16,0,0,0,707.3725,105.2625
|
||||
M805.0575,105.2625
|
||||
A16,16,0,0,0,805.0575,137.2625
|
||||
A16,16,0,0,0,805.0575,105.2625
|
||||
M170.10500000000002,154.10500000000002
|
||||
A16,16,0,0,0,170.10500000000002,186.10500000000002
|
||||
A16,16,0,0,0,170.10500000000002,154.10500000000002
|
||||
M218.9475,154.10500000000002
|
||||
A16,16,0,0,0,218.9475,186.10500000000002
|
||||
A16,16,0,0,0,218.9475,154.10500000000002
|
||||
M316.6325,154.10500000000002
|
||||
A16,16,0,0,0,316.6325,186.10500000000002
|
||||
A16,16,0,0,0,316.6325,154.10500000000002
|
||||
M414.31750000000005,154.10500000000002
|
||||
A16,16,0,0,0,414.31750000000005,186.10500000000002
|
||||
A16,16,0,0,0,414.31750000000005,154.10500000000002
|
||||
M463.16,154.10500000000002
|
||||
A16,16,0,0,0,463.16,186.10500000000002
|
||||
A16,16,0,0,0,463.16,154.10500000000002
|
||||
M512.0024999999999,154.10500000000002
|
||||
A16,16,0,0,0,512.0024999999999,186.10500000000002
|
||||
A16,16,0,0,0,512.0024999999999,154.10500000000002
|
||||
M707.3725,154.10500000000002
|
||||
A16,16,0,0,0,707.3725,186.10500000000002
|
||||
A16,16,0,0,0,707.3725,154.10500000000002
|
||||
M902.7425,154.10500000000002
|
||||
A16,16,0,0,0,902.7425,186.10500000000002
|
||||
A16,16,0,0,0,902.7425,154.10500000000002
|
||||
M218.9475,202.9475
|
||||
A16,16,0,0,0,218.9475,234.9475
|
||||
A16,16,0,0,0,218.9475,202.9475
|
||||
M267.79,202.9475
|
||||
A16,16,0,0,0,267.79,234.9475
|
||||
A16,16,0,0,0,267.79,202.9475
|
||||
M756.215,202.9475
|
||||
A16,16,0,0,0,756.215,234.9475
|
||||
A16,16,0,0,0,756.215,202.9475
|
||||
M853.9,202.9475
|
||||
A16,16,0,0,0,853.9,234.9475
|
||||
A16,16,0,0,0,853.9,202.9475
|
||||
M902.7425,202.9475
|
||||
A16,16,0,0,0,902.7425,234.9475
|
||||
A16,16,0,0,0,902.7425,202.9475
|
||||
M951.5849999999999,202.9475
|
||||
A16,16,0,0,0,951.5849999999999,234.9475
|
||||
A16,16,0,0,0,951.5849999999999,202.9475
|
||||
M72.42,251.79000000000002
|
||||
A16,16,0,0,0,72.42,283.79
|
||||
A16,16,0,0,0,72.42,251.79000000000002
|
||||
M218.9475,251.79000000000002
|
||||
A16,16,0,0,0,218.9475,283.79
|
||||
A16,16,0,0,0,218.9475,251.79000000000002
|
||||
M267.79,251.79000000000002
|
||||
A16,16,0,0,0,267.79,283.79
|
||||
A16,16,0,0,0,267.79,251.79000000000002
|
||||
M805.0575,251.79000000000002
|
||||
A16,16,0,0,0,805.0575,283.79
|
||||
A16,16,0,0,0,805.0575,251.79000000000002
|
||||
M951.5849999999999,251.79000000000002
|
||||
A16,16,0,0,0,951.5849999999999,283.79
|
||||
A16,16,0,0,0,951.5849999999999,251.79000000000002
|
||||
M72.42,300.6325
|
||||
A16,16,0,0,0,72.42,332.6325
|
||||
A16,16,0,0,0,72.42,300.6325
|
||||
M902.7425,300.6325
|
||||
A16,16,0,0,0,902.7425,332.6325
|
||||
A16,16,0,0,0,902.7425,300.6325
|
||||
M170.10500000000002,349.475
|
||||
A16,16,0,0,0,170.10500000000002,381.475
|
||||
A16,16,0,0,0,170.10500000000002,349.475
|
||||
M951.5849999999999,349.475
|
||||
A16,16,0,0,0,951.5849999999999,381.475
|
||||
A16,16,0,0,0,951.5849999999999,349.475
|
||||
M170.10500000000002,398.31750000000005
|
||||
A16,16,0,0,0,170.10500000000002,430.31750000000005
|
||||
A16,16,0,0,0,170.10500000000002,398.31750000000005
|
||||
M853.9,398.31750000000005
|
||||
A16,16,0,0,0,853.9,430.31750000000005
|
||||
A16,16,0,0,0,853.9,398.31750000000005
|
||||
M951.5849999999999,398.31750000000005
|
||||
A16,16,0,0,0,951.5849999999999,430.31750000000005
|
||||
A16,16,0,0,0,951.5849999999999,398.31750000000005
|
||||
M170.10500000000002,447.16
|
||||
A16,16,0,0,0,170.10500000000002,479.16
|
||||
A16,16,0,0,0,170.10500000000002,447.16
|
||||
M853.9,447.16
|
||||
A16,16,0,0,0,853.9,479.16
|
||||
A16,16,0,0,0,853.9,447.16
|
||||
M902.7425,447.16
|
||||
A16,16,0,0,0,902.7425,479.16
|
||||
A16,16,0,0,0,902.7425,447.16
|
||||
M72.42,496.0025
|
||||
A16,16,0,0,0,72.42,528.0025
|
||||
A16,16,0,0,0,72.42,496.0025
|
||||
M121.2625,496.0025
|
||||
A16,16,0,0,0,121.2625,528.0025
|
||||
A16,16,0,0,0,121.2625,496.0025
|
||||
M170.10500000000002,496.0025
|
||||
A16,16,0,0,0,170.10500000000002,528.0025
|
||||
A16,16,0,0,0,170.10500000000002,496.0025
|
||||
M853.9,496.0025
|
||||
A16,16,0,0,0,853.9,528.0025
|
||||
A16,16,0,0,0,853.9,496.0025
|
||||
M902.7425,496.0025
|
||||
A16,16,0,0,0,902.7425,528.0025
|
||||
A16,16,0,0,0,902.7425,496.0025
|
||||
M951.5849999999999,496.0025
|
||||
A16,16,0,0,0,951.5849999999999,528.0025
|
||||
A16,16,0,0,0,951.5849999999999,496.0025
|
||||
M72.42,544.845
|
||||
A16,16,0,0,0,72.42,576.845
|
||||
A16,16,0,0,0,72.42,544.845
|
||||
M121.2625,544.845
|
||||
A16,16,0,0,0,121.2625,576.845
|
||||
A16,16,0,0,0,121.2625,544.845
|
||||
M853.9,544.845
|
||||
A16,16,0,0,0,853.9,576.845
|
||||
A16,16,0,0,0,853.9,544.845
|
||||
M902.7425,544.845
|
||||
A16,16,0,0,0,902.7425,576.845
|
||||
A16,16,0,0,0,902.7425,544.845
|
||||
M72.42,593.6875
|
||||
A16,16,0,0,0,72.42,625.6875
|
||||
A16,16,0,0,0,72.42,593.6875
|
||||
M853.9,593.6875
|
||||
A16,16,0,0,0,853.9,625.6875
|
||||
A16,16,0,0,0,853.9,593.6875
|
||||
M902.7425,593.6875
|
||||
A16,16,0,0,0,902.7425,625.6875
|
||||
A16,16,0,0,0,902.7425,593.6875
|
||||
M951.5849999999999,593.6875
|
||||
A16,16,0,0,0,951.5849999999999,625.6875
|
||||
A16,16,0,0,0,951.5849999999999,593.6875
|
||||
M218.9475,691.3725
|
||||
A16,16,0,0,0,218.9475,723.3725
|
||||
A16,16,0,0,0,218.9475,691.3725
|
||||
M805.0575,691.3725
|
||||
A16,16,0,0,0,805.0575,723.3725
|
||||
A16,16,0,0,0,805.0575,691.3725
|
||||
M951.5849999999999,691.3725
|
||||
A16,16,0,0,0,951.5849999999999,723.3725
|
||||
A16,16,0,0,0,951.5849999999999,691.3725
|
||||
M756.215,740.215
|
||||
A16,16,0,0,0,756.215,772.215
|
||||
A16,16,0,0,0,756.215,740.215
|
||||
M805.0575,740.215
|
||||
A16,16,0,0,0,805.0575,772.215
|
||||
A16,16,0,0,0,805.0575,740.215
|
||||
M951.5849999999999,740.215
|
||||
A16,16,0,0,0,951.5849999999999,772.215
|
||||
A16,16,0,0,0,951.5849999999999,740.215
|
||||
M72.42,789.0575
|
||||
A16,16,0,0,0,72.42,821.0575
|
||||
A16,16,0,0,0,72.42,789.0575
|
||||
M121.2625,789.0575
|
||||
A16,16,0,0,0,121.2625,821.0575
|
||||
A16,16,0,0,0,121.2625,789.0575
|
||||
M316.6325,789.0575
|
||||
A16,16,0,0,0,316.6325,821.0575
|
||||
A16,16,0,0,0,316.6325,789.0575
|
||||
M805.0575,789.0575
|
||||
A16,16,0,0,0,805.0575,821.0575
|
||||
A16,16,0,0,0,805.0575,789.0575
|
||||
M902.7425,789.0575
|
||||
A16,16,0,0,0,902.7425,821.0575
|
||||
A16,16,0,0,0,902.7425,789.0575
|
||||
M72.42,837.9
|
||||
A16,16,0,0,0,72.42,869.9
|
||||
A16,16,0,0,0,72.42,837.9
|
||||
M170.10500000000002,837.9
|
||||
A16,16,0,0,0,170.10500000000002,869.9
|
||||
A16,16,0,0,0,170.10500000000002,837.9
|
||||
M267.79,837.9
|
||||
A16,16,0,0,0,267.79,869.9
|
||||
A16,16,0,0,0,267.79,837.9
|
||||
M365.475,837.9
|
||||
A16,16,0,0,0,365.475,869.9
|
||||
A16,16,0,0,0,365.475,837.9
|
||||
M658.53,837.9
|
||||
A16,16,0,0,0,658.53,869.9
|
||||
A16,16,0,0,0,658.53,837.9
|
||||
M707.3725,837.9
|
||||
A16,16,0,0,0,707.3725,869.9
|
||||
A16,16,0,0,0,707.3725,837.9
|
||||
M756.215,837.9
|
||||
A16,16,0,0,0,756.215,869.9
|
||||
A16,16,0,0,0,756.215,837.9
|
||||
M805.0575,837.9
|
||||
A16,16,0,0,0,805.0575,869.9
|
||||
A16,16,0,0,0,805.0575,837.9
|
||||
M853.9,837.9
|
||||
A16,16,0,0,0,853.9,869.9
|
||||
A16,16,0,0,0,853.9,837.9
|
||||
M902.7425,837.9
|
||||
A16,16,0,0,0,902.7425,869.9
|
||||
A16,16,0,0,0,902.7425,837.9
|
||||
M951.5849999999999,837.9
|
||||
A16,16,0,0,0,951.5849999999999,869.9
|
||||
A16,16,0,0,0,951.5849999999999,837.9
|
||||
M170.10500000000002,886.7425
|
||||
A16,16,0,0,0,170.10500000000002,918.7425
|
||||
A16,16,0,0,0,170.10500000000002,886.7425
|
||||
M365.475,886.7425
|
||||
A16,16,0,0,0,365.475,918.7425
|
||||
A16,16,0,0,0,365.475,886.7425
|
||||
M414.31750000000005,886.7425
|
||||
A16,16,0,0,0,414.31750000000005,918.7425
|
||||
A16,16,0,0,0,414.31750000000005,886.7425
|
||||
M463.16,886.7425
|
||||
A16,16,0,0,0,463.16,918.7425
|
||||
A16,16,0,0,0,463.16,886.7425
|
||||
M512.0024999999999,886.7425
|
||||
A16,16,0,0,0,512.0024999999999,918.7425
|
||||
A16,16,0,0,0,512.0024999999999,886.7425
|
||||
M658.53,886.7425
|
||||
A16,16,0,0,0,658.53,918.7425
|
||||
A16,16,0,0,0,658.53,886.7425
|
||||
M756.215,886.7425
|
||||
A16,16,0,0,0,756.215,918.7425
|
||||
A16,16,0,0,0,756.215,886.7425
|
||||
M853.9,886.7425
|
||||
A16,16,0,0,0,853.9,918.7425
|
||||
A16,16,0,0,0,853.9,886.7425
|
||||
M902.7425,886.7425
|
||||
A16,16,0,0,0,902.7425,918.7425
|
||||
A16,16,0,0,0,902.7425,886.7425
|
||||
M170.10500000000002,935.5849999999999
|
||||
A16,16,0,0,0,170.10500000000002,967.5849999999999
|
||||
A16,16,0,0,0,170.10500000000002,935.5849999999999
|
||||
M218.9475,935.5849999999999
|
||||
A16,16,0,0,0,218.9475,967.5849999999999
|
||||
A16,16,0,0,0,218.9475,935.5849999999999
|
||||
M463.16,935.5849999999999
|
||||
A16,16,0,0,0,463.16,967.5849999999999
|
||||
A16,16,0,0,0,463.16,935.5849999999999
|
||||
M560.845,935.5849999999999
|
||||
A16,16,0,0,0,560.845,967.5849999999999
|
||||
A16,16,0,0,0,560.845,935.5849999999999
|
||||
M658.53,935.5849999999999
|
||||
A16,16,0,0,0,658.53,967.5849999999999
|
||||
A16,16,0,0,0,658.53,935.5849999999999
|
||||
M707.3725,935.5849999999999
|
||||
A16,16,0,0,0,707.3725,967.5849999999999
|
||||
A16,16,0,0,0,707.3725,935.5849999999999
|
||||
M805.0575,935.5849999999999
|
||||
A16,16,0,0,0,805.0575,967.5849999999999
|
||||
A16,16,0,0,0,805.0575,935.5849999999999
|
||||
" fill="#FFFC00"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
@@ -1,78 +0,0 @@
|
||||
import argparse
|
||||
|
||||
positions = [
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 5, 13, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 15, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 16, 17, 18],
|
||||
[0, 1, 2, 3, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 5, 13, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
||||
]
|
||||
|
||||
BORDER = 56.42
|
||||
BORDER_C = 72.42
|
||||
MULT = 48.8425
|
||||
DIAMETER = 32
|
||||
SVG = '''<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" height="1024" version="1.1" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d=" M749.88,641.75 C763.31,649.46,754.85,644.24,749.88,641.75 M0,860.16 C0,950.64,73.36,1024,163.84,1024 L860.16,1024 C950.64,1024,1024,950.64,1024,860.16 L1024,163.84 C1024,73.36,950.64,0,860.16,0 L163.84,0 C73.36,0,0,73.36,0,163.84 L0,860.16" fill="#000" fill-rule="evenodd"/>
|
||||
<path d="M32,163.84 C32,91.03,91.03,32,163.84,32 L860.16,32 C932.97,32,992,91.03,992,163.84 L992,860.16 C992,932.97,932.97,992,860.16,992 L163.84,992 C91.03,992,32,932.97,32,860.16 L32,163.84
|
||||
{path}" fill="#FFFC00"/>
|
||||
</svg>
|
||||
'''
|
||||
|
||||
def points_to_svg(points):
|
||||
counter = 0
|
||||
path = ""
|
||||
points.sort()
|
||||
for r in range(len(positions)):
|
||||
for c in range(len(positions[r])):
|
||||
col = positions[r][c]
|
||||
if len(points) == 0:
|
||||
break
|
||||
if points[0] == counter:
|
||||
path += f"""M{col * MULT + BORDER_C},{r * MULT + BORDER}
|
||||
A16,16,0,0,0,{col * MULT + BORDER_C},{r * MULT + BORDER + DIAMETER}
|
||||
A16,16,0,0,0,{col * MULT + BORDER_C},{r * MULT + BORDER}
|
||||
"""
|
||||
points.pop(0)
|
||||
counter += 1
|
||||
return SVG.format(path=path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--points", type=str, help="Points to draw")
|
||||
parser.add_argument("--output", type=str, help="Output file")
|
||||
parser.add_argument("--show", action="store_true", help="Show SVG")
|
||||
parser.set_defaults(points=",".join([str(i) for i in range(212)]))
|
||||
args = parser.parse_args()
|
||||
points = args.points.split(",")
|
||||
points = [int(i) for i in points]
|
||||
svg = points_to_svg(points)
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
f.write(svg)
|
||||
if args.show:
|
||||
import subprocess, os, platform
|
||||
if platform.system() == 'Darwin': # macOS
|
||||
subprocess.call(('open', args.output))
|
||||
elif platform.system() == 'Windows': # Windows
|
||||
os.startfile(args.output)
|
||||
else: # linux variants
|
||||
subprocess.call(('xdg-open', args.output))
|
||||
if not args.show or not args.output:
|
||||
print(svg)
|
||||
@@ -1,15 +0,0 @@
|
||||
import os
|
||||
|
||||
from img_to_svg import img_to_svg
|
||||
|
||||
|
||||
files = os.listdir("./imgs/twitter")
|
||||
files = [os.path.join("./imgs/twitter", f) for f in files if f.endswith(".jpeg")]
|
||||
|
||||
for f in files:
|
||||
output_path = f.replace(".jpeg", ".svg")
|
||||
try:
|
||||
img_to_svg(f, output_path)
|
||||
except Exception as e:
|
||||
print(f"Error processing {f}")
|
||||
print(e)
|
||||
|
Before Width: | Height: | Size: 85 KiB |
@@ -17,7 +17,6 @@ if __name__ == "__main__":
|
||||
filename = args.filename
|
||||
token = args.token
|
||||
heights = get_heights(filename)
|
||||
print(f"Heights: {heights}")
|
||||
# drop the fist, last, and 12th bar
|
||||
heights = heights[1:11] + heights[12:-1]
|
||||
decoded = spotify_bar_decode(heights)
|
||||
|
||||
@@ -1,78 +1,45 @@
|
||||
from skimage import io
|
||||
from skimage.color import rgb2gray
|
||||
from skimage.filters import threshold_otsu
|
||||
from skimage.measure import label, regionprops
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as patches
|
||||
from skimage import io
|
||||
from skimage.color import rgb2gray
|
||||
from skimage.filters import threshold_otsu, gaussian
|
||||
from skimage.morphology import closing, square
|
||||
from skimage.measure import label, regionprops
|
||||
import matplotlib.pyplot as plt
|
||||
from skimage.color import rgb2gray
|
||||
import matplotlib.patches as patches
|
||||
def get_heights(filename: str) -> list:
|
||||
"""Open an image and return a list of the bar heights.
|
||||
Also saves three images: the processed binary image, the original image with drawings, and a smoothed binary image.
|
||||
"""
|
||||
from sklearn.cluster import KMeans
|
||||
|
||||
def get_heights(filename: str):
|
||||
image = io.imread(filename)
|
||||
im = rgb2gray(image)
|
||||
binary_im = im > threshold_otsu(im)
|
||||
smooth_im = gaussian(binary_im.astype(float), sigma=1)
|
||||
morph_im = closing(smooth_im > 0.5, square(3))
|
||||
|
||||
# Apply Gaussian smoothing to binary image to make bars look rounder
|
||||
smooth_im = gaussian(binary_im, sigma=2)
|
||||
# Threshold again to obtain a smoothed binary
|
||||
smooth_binary = smooth_im > 0.5
|
||||
labeled = label(smooth_binary)
|
||||
bar_dimensions = [r.bbox for r in regionprops(labeled)]
|
||||
bar_dimensions.sort(key=lambda x: x[1]) # Sort left to right
|
||||
# The first object (spotify logo) is the max height of the bars
|
||||
logo = bar_dimensions[0]
|
||||
max_height = logo[2] - logo[0]
|
||||
sequence = []
|
||||
# Create figure and axis for drawing
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(smooth_binary, cmap='gray')
|
||||
# Draw rectangle around logo
|
||||
logo_rect = patches.Rectangle(
|
||||
(logo[1], logo[0]),
|
||||
logo[3]-logo[1],
|
||||
logo[2]-logo[0],
|
||||
linewidth=2,
|
||||
edgecolor='yellow',
|
||||
facecolor='none'
|
||||
)
|
||||
ax.add_patch(logo_rect)
|
||||
# Add 'Logo' text near the rectangle
|
||||
ax.text(logo[1], logo[0] - 10, 'Logo', color='yellow', fontsize=12, weight='bold')
|
||||
# Draw bars and center markers
|
||||
for bar in bar_dimensions[1:]:
|
||||
height = bar[2] - bar[0]
|
||||
ratio = height / max_height
|
||||
ratio *= 8
|
||||
ratio //= 1
|
||||
val = int(ratio - 1)
|
||||
sequence.append(val)
|
||||
# Draw rectangle around bar
|
||||
rect = patches.Rectangle(
|
||||
(bar[1], bar[0]),
|
||||
bar[3]-bar[1],
|
||||
bar[2]-bar[0],
|
||||
linewidth=1,
|
||||
edgecolor='red',
|
||||
facecolor='none'
|
||||
)
|
||||
ax.add_patch(rect)
|
||||
# Draw center marker (white circle)
|
||||
center_x = (bar[1] + bar[3]) / 2
|
||||
center_y = (bar[0] + bar[2]) / 2
|
||||
center_marker = patches.Circle((center_x, center_y), radius=5, color='black')
|
||||
ax.add_patch(center_marker)
|
||||
# Save processed binary image used for calculations
|
||||
plt.imsave('processed_binary_image.png', binary_im, cmap='gray')
|
||||
# Save smoothed binary image
|
||||
plt.imsave('img_smooth.png', smooth_binary, cmap='gray')
|
||||
# Save image with drawings
|
||||
plt.axis('off')
|
||||
plt.savefig('image_with_drawings.png', bbox_inches='tight', pad_inches=0)
|
||||
plt.close()
|
||||
return sequence
|
||||
labeled = label(morph_im)
|
||||
bar_dims = [r.bbox for r in regionprops(labeled)]
|
||||
bar_dims.sort(key=lambda x: x[1]) # left to right
|
||||
|
||||
bars = bar_dims[1:] # skip logo
|
||||
bar_heights_raw = []
|
||||
|
||||
for bar in bars:
|
||||
top, left, bottom, right = bar
|
||||
effective_height = bottom - top # use bounding box height directly
|
||||
bar_heights_raw.append(effective_height)
|
||||
print(len(bars))
|
||||
# Cluster measured heights to 8 clusters representing discrete bar levels
|
||||
bar_heights_raw_np = np.array(bar_heights_raw).reshape(-1, 1)
|
||||
|
||||
kmeans = KMeans(n_clusters=8, random_state=0).fit(bar_heights_raw_np)
|
||||
cluster_centers = np.sort(kmeans.cluster_centers_.flatten())
|
||||
|
||||
# Assign each bar height to closest cluster center index (0 to 7)
|
||||
predicted_levels = []
|
||||
for h in bar_heights_raw:
|
||||
diffs = np.abs(cluster_centers - h)
|
||||
closest_cluster = np.argmin(diffs)
|
||||
predicted_levels.append(closest_cluster)
|
||||
|
||||
|
||||
print(len(predicted_levels))
|
||||
return predicted_levels
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,11 +0,0 @@
|
||||
import crc8
|
||||
|
||||
hash = crc8.crc8()
|
||||
media_ref = 67775490487
|
||||
ref_bytes = media_ref.to_bytes(5, byteorder="big")
|
||||
print(ref_bytes)
|
||||
# b'\x0f\xc7\xbb\xe9\xb7'
|
||||
hash.update(ref_bytes)
|
||||
check_bits = hash.digest()
|
||||
print(check_bits)
|
||||
# b'\x0c'
|
||||
@@ -1,52 +0,0 @@
|
||||
from skimage import io
|
||||
from skimage.measure import label, regionprops
|
||||
from skimage.filters import threshold_otsu
|
||||
from skimage.color import rgb2gray
|
||||
|
||||
|
||||
from skimage import io
|
||||
from skimage.color import rgb2gray
|
||||
from skimage.filters import threshold_sauvola
|
||||
from skimage.exposure import equalize_adapthist
|
||||
from skimage.measure import label, regionprops
|
||||
from skimage.morphology import closing, square
|
||||
|
||||
def get_heights(filename: str) -> list:
|
||||
"""Open an image and return a list of the bar heights."""
|
||||
# Load image and convert to grayscale
|
||||
image = io.imread(filename)
|
||||
im = rgb2gray(image)
|
||||
|
||||
# Apply adaptive histogram equalization to enhance contrast
|
||||
im_eq = equalize_adapthist(im, clip_limit=0.03)
|
||||
|
||||
# Adaptive thresholding using Sauvola method
|
||||
window_size = 25 # Adjust window size if needed
|
||||
thresh_sauvola = threshold_sauvola(im_eq, window_size=window_size)
|
||||
binary_im = im_eq > thresh_sauvola
|
||||
|
||||
# Morphological closing to fill gaps and clean noise
|
||||
binary_im = closing(binary_im, square(3))
|
||||
|
||||
# Label connected components
|
||||
labeled = label(binary_im)
|
||||
|
||||
# Get bounding boxes for each detected object
|
||||
bar_dimensions = [r.bbox for r in regionprops(labeled)]
|
||||
|
||||
# Sort bounding boxes by horizontal position (xmin)
|
||||
bar_dimensions.sort(key=lambda x: x[1])
|
||||
|
||||
# Use the first detected object (logo) as max height reference
|
||||
logo = bar_dimensions[0]
|
||||
max_height = logo[2] - logo[0]
|
||||
|
||||
sequence = []
|
||||
for bar in bar_dimensions[1:]:
|
||||
height = bar[2] - bar[0]
|
||||
ratio = height / max_height
|
||||
ratio *= 8
|
||||
ratio = int(ratio) # truncate decimal part
|
||||
sequence.append(ratio - 1)
|
||||
|
||||
return sequence
|
||||