Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to README.md and requirements #2

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@
# songoku
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)

### [v 0.1](https://www.youtube.com/watch?v=H4L9yENEQbI)
Working release
Working release

## Installation

(Optional) Setup a virtual environment to install the necessary packages.

```bash
virtualenv venv
source venv/bin/activate
```

Install the packages listed in the requirements file.

```bash
pip install -r requirements.txt
```

Run the application.

```bash
python camera.py
```

## TODO

- [x] Guess numbers every 10 frames (it still grabs every frame of video).
- [ ] Complete README.md.
- [ ] Create `main.py` file, rather than having to run `camera.py` (unclear that this is main until reading the source).
- [ ] Make numbers less shaky (better contour grabbing?).
- [ ] Make it so it only guesses the numbers every ~20 frames? Maybe guesses them really fast at the beginning and once it has it figured out it slows down.
11 changes: 0 additions & 11 deletions TODO.txt

This file was deleted.

66 changes: 38 additions & 28 deletions helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@

def crop_from_points(img, corners, make_square=True):

cnt = np.array([
corners[0],
corners[1],
corners[2],
corners[3]
])
cnt = np.array([corners[0], corners[1], corners[2], corners[3]])

rect = cv2.minAreaRect(cnt)
center, size, theta = rect

# Angle correction
if theta < -45:
theta += 90

rect = (center, size, theta)

box = cv2.boxPoints(rect)
Expand All @@ -30,8 +25,8 @@ def crop_from_points(img, corners, make_square=True):
width = int(rect[1][0])
height = int(rect[1][1])

src_pts = np.float32([corners[0],corners[1],corners[2],corners[3]])
dst_pts = np.float32([[0,0],[width,0],[0,height],[width,height]])
src_pts = np.float32([corners[0], corners[1], corners[2], corners[3]])
dst_pts = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

# the perspective transformation matrix
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
Expand All @@ -43,15 +38,16 @@ def crop_from_points(img, corners, make_square=True):

if make_square is True:
try:
warped = cv2.resize(warped, (max(width, height), max(width, height)), interpolation=cv2.INTER_CUBIC)
warped = cv2.resize(
warped,
(max(width, height), max(width, height)),
interpolation=cv2.INTER_CUBIC,
)

except Exception as e:
print(e)

transformation_data = {
'matrix' : M,
'original_shape': (height, width)
}
transformation_data = {"matrix": M, "original_shape": (height, width)}

return warped, transformation_data

Expand All @@ -60,12 +56,16 @@ def perspective_transform(img, transformation_matrix, original_shape=None):
warped = img

if original_shape is not None:
if original_shape[0]>0 and original_shape[1]>0:
warped = cv2.resize(warped, (original_shape[1], original_shape[0]), interpolation=cv2.INTER_CUBIC)
if original_shape[0] > 0 and original_shape[1] > 0:
warped = cv2.resize(
warped,
(original_shape[1], original_shape[0]),
interpolation=cv2.INTER_CUBIC,
)

white_image = np.zeros((640, 480, 3), np.uint8)

white_image[:,:,:] = 255
white_image[:, :, :] = 255

# warped = cv2.warpPerspective(warped, transformation_matrix, (640, 480), borderMode=cv2.BORDER_TRANSPARENT)
warped = cv2.warpPerspective(warped, transformation_matrix, (640, 480))
Expand All @@ -80,7 +80,9 @@ def blend_non_transparent(face_img, overlay_img):
overlay_mask = cv2.threshold(gray_overlay, 1, 255, cv2.THRESH_BINARY)[1]

# Let's shrink and blur it a little to make the transitions smoother...
overlay_mask = cv2.erode(overlay_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)))
overlay_mask = cv2.erode(
overlay_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
)
overlay_mask = cv2.blur(overlay_mask, (3, 3))

# And the inverse mask, that covers all the black (background) pixels
Expand All @@ -107,10 +109,10 @@ def crop_minAreaRect(src, rect):
if theta < -45:
theta += 90

# Convert to int
# Convert to int
center, size = tuple(map(int, center)), tuple(map(int, size))
# Get rotation matrix for rectangle
M = cv2.getRotationMatrix2D( center, theta, 1)
M = cv2.getRotationMatrix2D(center, theta, 1)
# Perform rotation on src image
dst = cv2.warpAffine(src, M, (src.shape[1], src.shape[0]))
out = cv2.getRectSubPix(dst, size, center)
Expand All @@ -121,17 +123,25 @@ def resize_to_square(image, goal_dimension=28, border=2):
height, width = image.shape[0], image.shape[1]
smol = max(height, width)

proportion = goal_dimension/smol
proportion = goal_dimension / smol

BLACK = [0, 0, 0]
constant = cv2.copyMakeBorder(image, border, border, border, border, cv2.BORDER_CONSTANT, value=BLACK)
constant = cv2.copyMakeBorder(
image, border, border, border, border, cv2.BORDER_CONSTANT, value=BLACK
)
background = np.zeros((goal_dimension, goal_dimension), dtype=np.int)
resized = cv2.resize(constant, (int(round(width*proportion)), int(round(height*proportion))), interpolation=cv2.INTER_AREA)

x_offset=(goal_dimension-resized.shape[1])//2
y_offset=(goal_dimension-resized.shape[0])//2
resized = cv2.resize(
constant,
(int(round(width * proportion)), int(round(height * proportion))),
interpolation=cv2.INTER_AREA,
)

x_offset = (goal_dimension - resized.shape[1]) // 2
y_offset = (goal_dimension - resized.shape[0]) // 2

background[y_offset:y_offset+resized.shape[0], x_offset:x_offset+resized.shape[1]] = resized
background[
y_offset : y_offset + resized.shape[0], x_offset : x_offset + resized.shape[1]
] = resized

final = background
return np.uint8(final)
Expand Down Expand Up @@ -170,7 +180,7 @@ def instance(self):
return self._instance

def __call__(self):
raise TypeError('Singletons must be accessed through `instance()`.')
raise TypeError("Singletons must be accessed through `instance()`.")

def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
Loading