Spaces:
Sleeping
Sleeping
import sys | |
from io import StringIO | |
import streamlit as st | |
import numpy as np | |
from PIL import Image, ImageDraw, ImageColor | |
from canvas import * | |
from streamlit_ace import st_ace | |
import extra_streamlit_components as stx | |
from sewar.full_ref import uqi | |
from lines import * | |
from triangle import * | |
st.set_page_config(page_title="How to play Shape Puzzle", page_icon=":notebook:") | |
with st.sidebar: | |
color = st.color_picker('color picker', '#00f900', key='l_c') | |
st.write(ImageColor.getrgb(color)) | |
st.header("Chapter 1: Lines and Triangles") | |
st.write("##") | |
st.divider() | |
with st.expander("Tutorial No.1: Line segments"): | |
st.markdown("#### Let's start with playing with line-segments") | |
st.markdown( | |
""" | |
1. We will firstly draw a simple line-segment. The easiest way to do so is using our line function: | |
```python | |
line2P(start, point) | |
``` | |
- In the code window below, define two points on the canvas by: | |
```python | |
a = (-100, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (100, 0) ## the x-axis is 100 and y-axis is 0 | |
line2P(a, b) ## then call our line2P function to draw the line | |
``` | |
You should see a horizontal line-segment in the canvas. | |
Feel free to change the color or the width of drawing by refering the "Functions" page from side bar. | |
2. Our 2nd Line function, LineDraw(): | |
Sometimes, it might be easier to just start from a single point, but thinking about the direction and the length of drawing a | |
line segment. This is more intuitive for the real drawing scenario. | |
- In the code window below, define a point and the length and angle you want to draw : | |
```python | |
a = (-100, 0) ## the x-axis is -100 and y-axis is 0 | |
angle = 45 ## 45 degree anti-clock wise | |
length = 200 ## length of the drawing | |
lineDraw(a, angle, length, width=50) ## then call our lineDraw function to draw the line | |
## We can also specify the width of drawing by passing parameter explicitly. | |
``` | |
You should see a slant line-segment in the canvas. | |
3. Release the power of for-loop: | |
The most powerful part of drawing through code is the capability of producing iterative graphs. | |
The more detailed instruction about Python for-loops, please check [here](https://www.w3schools.com/python/python_for_loops.asp) | |
- In the code window below, define a startinig point and using for-loop and lineDraw: | |
```python | |
c = (-50,-100) ## The starting point to draw | |
lst = [c] ## Create a list for later reference | |
for i in range (100): ## Iterate 100 rounds | |
l = lineDraw(lst[-1], i*125, 300, (212, 16, 16), width=2) ## Try to figure out what are we doing here? | |
lst.append(l['end']) ## add the end-point of the line drawn to the list for the next iteration | |
``` | |
4. Now, see if you can produce a shape stated in "target shape": | |
```python | |
s = (0,0) ## The starting point | |
n = 8 ## | |
lst = [s] | |
#### Start your for-loop here #### | |
#### End of your for-loop #### | |
``` | |
Having fun!! | |
""" | |
) | |
st.divider() | |
st.markdown("###### Write your code here") | |
## Code input | |
code1 = st_ace(language="python", theme="tomorrow_night_bright", keybinding="vscode", font_size=14, tab_size=4, show_gutter=True, min_lines=10, key="ace",) | |
o1, o2 = st.columns(2) | |
if code1: | |
ImageDraw.Draw(img).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
redirected_output = sys.stdout = StringIO() | |
try: | |
exec(code1) | |
result = str(redirected_output.getvalue()) | |
st.code(result) | |
except Exception as e: | |
st.code(str(e)) | |
with o1: | |
st.markdown("##### Target Shape:"); target = Image.open('image/T1_t.jpg') | |
t2 = target.resize((c_length,c_height)) | |
ImageDraw.Draw(img_t).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
img_t.paste(t2); st.image(img_t); st.session_state['imt'] = np.array(img_t) | |
with o2: | |
st.markdown("##### Output Shape"); st.image(img, caption=''); st.session_state['imo'] = np.array(img) | |
sim = round(uqi(st.session_state['imt'],st.session_state['imo']),4) | |
st.write(f"The similarity score between target and output: {sim}") | |
with st.expander("Tutorial No.2: Triangles and Transformations 1"): | |
st.markdown("Now, we will start to draw more cool shapes") | |
st.markdown( | |
""" | |
1. The simplest way to draw a triangle is to define three points on the canvas: | |
- In the code window below, define two points on the canvas by: | |
```python | |
a = (-100, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (100, 0) ## the x-axis is 100 and y-axis is 0 | |
c = (0, 200) ## the x-axis is 0 and y-axis is 200 | |
triangle_base(a,b,c, fill = (0, 249, 0), color=(0,0,0)) ## then call our basic triangle function to draw the shape | |
``` | |
You should see a isosceles triangle in the canvas. | |
In the triangle_base() function, we have two parameters for coloring: | |
-- the "fill" is for the color filled in the triangle | |
-- the "color" is color of the edge of the triangle | |
2. Our 2nd Triangle function, triangle_LP(): | |
Again, it might be easier to just start from a line, but thinking about another point to draw a | |
triangle. This is convient for some scenario when iteration applies. | |
- In the code window below, try the follow drawing: | |
```python | |
for i in range (10): # We create an iteration of 10 | |
# Each iteration, draw a line with one different end point per iter | |
l = line2P((100,0+i*10),(-300,100), (0, 249, 0)) | |
# then for each different line drawn, touch it to a fixed point (150,150) to form a triangle | |
triangle_LP(l, (150,150), (0, 249, 0)) | |
``` | |
You should see a repeated triangle shape in the canvas. | |
3. Transform of shapes 1: Rescale: | |
Shape transformations are very helpful functions in drawing shapes. | |
The first transformation we are trying is Rescale, | |
- In the code window below, define a startinig triangle from triangle_base() and then scale it: | |
```python | |
a = (-100, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (100, 0) ## the x-axis is 100 and y-axis is 0 | |
c = (0, 200) ## the x-axis is 0 and y-axis is 200 | |
### Our initial triangle, give it a name, t | |
t = triangle_base(a,b,c, fill = (0, 249, 0), color=(0, 249, 0)) | |
### we rescale it with half size | |
### 1. We use the default color here, which was filled with canvas color and edge with black | |
### 2. We choose redraw=False, this means keep the original triangle t | |
##### 2.5 If we are passing redraw=True, the t will disappear. | |
t2 = rescale_c(t, alpha=0.5, redraw=False) | |
``` | |
You might already see a chance of creating a for-loop for some great design? | |
The rescale function we used above is rescaling based on centre of triangle, we can also use another | |
rescale function rescale_p() to specify the point we want to base on for rescaling. | |
- In the code window below, following the code from above, paste the next snippet | |
```python | |
a = (-100, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (100, 0) ## the x-axis is 100 and y-axis is 0 | |
c = (0, -200) ## the x-axis is 0 and y-axis is 200 | |
### Our initial triangle, give it a name, t | |
t3 = triangle_base(a,b,c, fill = (201, 64, 26), color=(201, 64, 26)) | |
### we rescale it with half size, but at different point | |
t4 = rescale_p(t3, 'p2', alpha=0.5, redraw=False) | |
``` | |
4. Transform of shapes 2: Translation: | |
The second transformation we are introducing is translation, | |
- In the code window below, define a startinig triangle from triangle_base() and then Translate it | |
to different location: | |
```python | |
a = (-200, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (10, 0) ## the x-axis is 100 and y-axis is 0 | |
c = (0, -100) ## the x-axis is 0 and y-axis is 200 | |
### Our initial triangle, give it a name, t | |
t5 = triangle_base(a,b,c, fill = (201, 64, 26), color=(201, 64, 26)) | |
## We use vector here to specify the direction and magnitute of translation. | |
## The translate_o() function is traslating triangles by a vector defined from the | |
## origin. i.e. the center of the canvas. | |
t6 = translate_o(t3, vector = (100,150), redraw=False) | |
``` | |
Now we should try the effect of translate by a vector defined from a point of the triangle | |
- In the code window below, define a startinig triangle from triangle_base() and then Translate it | |
to different location, using translate_p() function: | |
```python | |
a = (-20, 0) ## the x-axis is -100 and y-axis is 0 | |
b = (10, 0) ## the x-axis is 100 and y-axis is 0 | |
c = (0, -100) ## the x-axis is 0 and y-axis is 200 | |
### Our initial triangle, give it a name, t | |
t7 = triangle_base(a,b,c, fill = (201, 64, 26), color=(201, 64, 26)) | |
translate_p(t7, vector = (-10,10), point = 'p2', redraw=False) | |
``` | |
The code above specify "P2" as origin of translation rather than center of canvas | |
5. Using data for more complicated design: | |
Read the code below and check out the output from a more specific design | |
```python | |
b_line = line2P((-200,-160),(200,-160),color='black') # set the baseline | |
tpoint = (0,200) # set the top point of the triangle | |
# Create the first triangle | |
t1 = triangle_LP(b_line,tpoint,color='black',fill='black') | |
# Translate the triangle_LP | |
down_vector = (0,-50) | |
t2 = translate_o(t1, down_vector,fill=None, redraw=False) | |
# Redraw the edge of the second triangle | |
l1 = line2P(t2['p1'], t2['p2'], color='white', width=10) | |
l2 = line2P(t2['p1'], t2['p3'], color='white', width=10) | |
l3 = line2P(t2['p2'], t2['p3'], color='white', width=10) | |
## Find two intersections on the baseline | |
p1 = lines_intersection(l2, b_line) | |
p2 = lines_intersection(l3, b_line) | |
## Redraw the line-segment with information | |
l4 = line2P(p1, t2['p1'], color = 'black', width=10) | |
l5 = line2P(p2, t2['p2'], color = 'black', width=10) | |
l3 = line2P(t2['p1'], t2['p2'], color = 'black', width=10) | |
``` | |
Feel free to play around the code above to try different design. | |
6. Try to design/create a shape like the target shape :) | |
""" | |
) | |
st.divider() | |
st.markdown("###### Write your code here") | |
## Code input | |
code2 = st_ace(language="python", theme="tomorrow_night_bright", keybinding="vscode", font_size=14, tab_size=4, show_gutter=True, min_lines=10, key="ace2",) | |
o1, o2 = st.columns(2) | |
if code2: | |
ImageDraw.Draw(img).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
redirected_output = sys.stdout = StringIO() | |
try: | |
exec(code2) | |
result = str(redirected_output.getvalue()) | |
st.code(result) | |
except Exception as e: | |
st.code(str(e)) | |
with o1: | |
st.markdown("##### Target Shape:"); target = Image.open('image/T2_t.jpg') | |
t2 = target.resize((c_length,c_height)) | |
ImageDraw.Draw(img_t).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
img_t.paste(t2); st.image(img_t); st.session_state['imt'] = np.array(img_t) | |
with o2: | |
st.markdown("##### Output Shape"); st.image(img, caption=''); st.session_state['imo'] = np.array(img) | |
sim = round(uqi(st.session_state['imt'],st.session_state['imo']),4) | |
st.write(f"The similarity score between target and output: {sim}") | |
with st.expander("Tutorial No.3: Transformation 2, Rotation and Reflection"): | |
st.markdown("We will continues on more transformations that helps us to create shape designs") | |
st.markdown( | |
""" | |
1. Rotation by a point on the canvas: | |
- Copy and past the code below to the code window: | |
```python | |
P1=(100,100); P2=(200,50); P3=(-10,-50) | |
t = triangle_base(P1, P2, P3, 'red') | |
t1 = rotation(t,redraw=False, fill='blue') ## Rotation by the origin (0,0), default | |
# rotate 90 degree based on a point from the triangle | |
t2 = rotation(t, t['p1'], redraw = False, fill = 'yellow') | |
# rotate 120 degree based on a point on the canvas | |
t3 = rotation(t, (-50, 100), angle=120, redraw=False, fill='orange') | |
``` | |
You should see differernt rotations with different color | |
Carefully read the code and comments, figuring out: | |
-- What is the parameter that control the point of rotation | |
-- what is the parameter that control the degree of rotation | |
2. Reflection by a line on the canvas: | |
- Copy and past the code below to the code window: | |
```python | |
P1=(100,100); P2=(200,50); P3=(-10,-50) | |
t = triangle_base(P1, P2, P3, 'red') | |
## Define different lines | |
l1 = line2P(t['p2'],t['p3'], 'green') | |
l2 = line2P((0,0),(0,200), 'yellow') | |
l3 = line2P((100,0),(200,0), 'orange') | |
## Reflect by different lines: | |
t3 = reflection(t, l1, redraw=False, fill='green') | |
t4 = reflection(t, l2, redraw=False, fill='yellow') | |
t5 = reflection(t, l3, redraw=False, fill='orange') | |
``` | |
You should see differernt reflection with different color | |
Carefully read the code and comments, figuring out: | |
-- What is the parameter that control the line of reflection | |
3. Translations with for loops | |
Let's review the power of our favourate for-loops! | |
- Copy and past the code below to the code window: | |
```python | |
## You can define the colors you are using at the beginning | |
## To choose the color, using color picker to get the hex code or RGB values | |
B_color = 'white' | |
P_color = (11, 129, 11) | |
## Define an initial triangle | |
start = triangle_base((20,50),(20,80),(35,22.3),color=B_color) | |
start = rescale_c(start,3,color=B_color) | |
# try to reflect 1st time | |
a = reflection(start,line2P(start['p1'],start['p2'],P_color), | |
redraw=False,color=P_color) | |
## Looping around | |
for i in range(12): | |
a = reflection(a,line2P(a['p2'],a['p3']),redraw=False,color=P_color) | |
a = reflection(a,line2P(a['p1'],a['p3']),redraw=False,color=P_color) | |
## After reflection you might want to fine-tune to add on another rotation | |
reflection(a,line2P(a['p2'],a['p3'],P_color),redraw=False,color=P_color) | |
``` | |
You might also try some different colors for the flower --- | |
4. Now, see if you can produce a shape stated in "target shape": | |
""" | |
) | |
st.divider() | |
st.markdown("###### Write your code here") | |
## Code input | |
code3 = st_ace(language="python", theme="tomorrow_night_bright", keybinding="vscode", font_size=14, tab_size=4, show_gutter=True, min_lines=10, key="ace3",) | |
o1, o2 = st.columns(2) | |
if code3: | |
ImageDraw.Draw(img).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
redirected_output = sys.stdout = StringIO() | |
try: | |
exec(code3) | |
result = str(redirected_output.getvalue()) | |
st.code(result) | |
except Exception as e: | |
st.code(str(e)) | |
with o1: | |
st.markdown("##### Target Shape:"); target = Image.open('image/T3_t.jpg') | |
t3 = target.resize((c_length,c_height)) | |
ImageDraw.Draw(img_t).rectangle([(0, 0), (c_length,c_height)], fill = c_color, outline = c_outline, width=2) | |
img_t.paste(t3); st.image(img_t); st.session_state['imt'] = np.array(img_t) | |
with o2: | |
st.markdown("##### Output Shape"); st.image(img, caption=''); st.session_state['imo'] = np.array(img) | |
sim = round(uqi(st.session_state['imt'],st.session_state['imo']),4) | |
st.write(f"The similarity score between target and output: {sim}") |