Spaces:
Configuration error
Configuration error
Merge pull request #1 from Danila-Pechenev/app
Browse files- .github/workflows/cd.yml +19 -0
- .github/workflows/ci.yml +48 -0
- .gitignore +2 -0
- README.md +3 -0
- __init__.py +0 -0
- app/__init__.py +0 -0
- app/app.py +50 -0
- app/model.py +29 -0
- app/requirements.txt +4 -0
- app/user_data/.gitkeep +0 -0
- setup.cfg +2 -0
- telegram_bot/__init__.py +0 -0
- telegram_bot/bot.py +47 -0
- telegram_bot/user_data/.gitkeep +0 -0
- test/__init__.py +0 -0
- test/test_images/test1.jpg +0 -0
- test/test_images/test2.png +0 -0
- test/test_images/test3.jpeg +0 -0
- test/test_model.py +36 -0
.github/workflows/cd.yml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: CD
|
2 |
+
|
3 |
+
|
4 |
+
on:
|
5 |
+
push:
|
6 |
+
branches: [main]
|
7 |
+
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
sync-to-hub:
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
steps:
|
13 |
+
- uses: actions/checkout@v3
|
14 |
+
with:
|
15 |
+
fetch-depth: 0
|
16 |
+
- name: Push to hub
|
17 |
+
env:
|
18 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
19 |
+
run: git push --force https://dpechenev:$HF_TOKEN@huggingface.co/spaces/dpechenev/low_light_image_enhancement main
|
.github/workflows/ci.yml
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: CI
|
2 |
+
|
3 |
+
on: [push, pull_request]
|
4 |
+
|
5 |
+
jobs:
|
6 |
+
lint:
|
7 |
+
name: Linter
|
8 |
+
runs-on: ubuntu-latest
|
9 |
+
steps:
|
10 |
+
- uses: actions/checkout@v3
|
11 |
+
- name: Run linter
|
12 |
+
uses: psf/black@stable
|
13 |
+
with:
|
14 |
+
options: "--check --verbose -l 120"
|
15 |
+
src: "./app"
|
16 |
+
version: "~= 22.0"
|
17 |
+
mypy:
|
18 |
+
name: Mypy
|
19 |
+
runs-on: ubuntu-latest
|
20 |
+
steps:
|
21 |
+
- uses: actions/checkout@v3
|
22 |
+
- name: Set up Python 3.10
|
23 |
+
uses: actions/setup-python@v4
|
24 |
+
with:
|
25 |
+
python-version: '3.10'
|
26 |
+
- name: Install dependencies
|
27 |
+
run: |
|
28 |
+
pip install mypy
|
29 |
+
pip install -r app/requirements.txt
|
30 |
+
python3 -m pip install types-Pillow
|
31 |
+
- name: Run mypy
|
32 |
+
run: mypy .
|
33 |
+
test:
|
34 |
+
name: Tests
|
35 |
+
runs-on: ubuntu-latest
|
36 |
+
timeout-minutes: 60
|
37 |
+
steps:
|
38 |
+
- uses: actions/checkout@v3
|
39 |
+
- name: Set up Python 3.10
|
40 |
+
uses: actions/setup-python@v4
|
41 |
+
with:
|
42 |
+
python-version: '3.10'
|
43 |
+
- name: Install dependencies
|
44 |
+
run: |
|
45 |
+
pip install pytest
|
46 |
+
pip install -r app/requirements.txt
|
47 |
+
- name: Run tests
|
48 |
+
run: pytest
|
.gitignore
CHANGED
@@ -127,3 +127,5 @@ dmypy.json
|
|
127 |
|
128 |
# Pyre type checker
|
129 |
.pyre/
|
|
|
|
|
|
127 |
|
128 |
# Pyre type checker
|
129 |
.pyre/
|
130 |
+
|
131 |
+
.idea/
|
README.md
CHANGED
@@ -1,2 +1,5 @@
|
|
1 |
# low-light-image-enhancement
|
2 |
Mini-application for low-light image enhancement based on keras-io/lowlight-enhance-mirnet model & Streamlit
|
|
|
|
|
|
|
|
1 |
# low-light-image-enhancement
|
2 |
Mini-application for low-light image enhancement based on keras-io/lowlight-enhance-mirnet model & Streamlit
|
3 |
+
|
4 |
+
## Description
|
5 |
+
Photos are often taken in poor light. This tool will help you lighten the image using a neural network.
|
__init__.py
ADDED
File without changes
|
app/__init__.py
ADDED
File without changes
|
app/app.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from tensorflow import keras
|
3 |
+
from PIL import Image
|
4 |
+
import io
|
5 |
+
|
6 |
+
import model
|
7 |
+
|
8 |
+
|
9 |
+
def configure():
|
10 |
+
st.set_page_config(page_title="Low-light image enhancement")
|
11 |
+
if "model" not in st.session_state:
|
12 |
+
st.session_state["model"]: keras.Model = model.create_model()
|
13 |
+
|
14 |
+
|
15 |
+
def describe_service():
|
16 |
+
st.title("Low-light image enhancement")
|
17 |
+
st.subheader("Just upload your low-light image and get the processed one!")
|
18 |
+
|
19 |
+
|
20 |
+
@st.experimental_memo
|
21 |
+
def call_model(uploaded_file: io.BytesIO) -> Image.Image:
|
22 |
+
return model.run_model(uploaded_file, st.session_state["model"])
|
23 |
+
|
24 |
+
|
25 |
+
def process_image():
|
26 |
+
uploaded_file = st.file_uploader(
|
27 |
+
label="Choose a file (you can upload new files without refreshing the page)",
|
28 |
+
type=["png", "jpg", "jpeg"],
|
29 |
+
)
|
30 |
+
if uploaded_file:
|
31 |
+
placeholder = st.empty()
|
32 |
+
placeholder.info("The image is being processed. It may take some time. Wait, please...")
|
33 |
+
image = call_model(uploaded_file)
|
34 |
+
placeholder.empty()
|
35 |
+
placeholder.image(image)
|
36 |
+
image_bytes = io.BytesIO()
|
37 |
+
image.save(image_bytes, format="png")
|
38 |
+
st.download_button(
|
39 |
+
label="Download lightened image", data=image_bytes, file_name="lightened.png", mime="image/png"
|
40 |
+
)
|
41 |
+
|
42 |
+
|
43 |
+
def main():
|
44 |
+
describe_service()
|
45 |
+
process_image()
|
46 |
+
|
47 |
+
|
48 |
+
if __name__ == "__main__":
|
49 |
+
configure()
|
50 |
+
main()
|
app/model.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import from_pretrained_keras
|
2 |
+
from tensorflow import keras
|
3 |
+
from PIL import Image
|
4 |
+
import numpy as np
|
5 |
+
import io
|
6 |
+
import os
|
7 |
+
|
8 |
+
|
9 |
+
def create_model() -> keras.Model:
|
10 |
+
return from_pretrained_keras("keras-io/lowlight-enhance-mirnet")
|
11 |
+
|
12 |
+
|
13 |
+
def run_model(image_bytes: io.BytesIO, model: keras.Model) -> Image.Image:
|
14 |
+
image = Image.open(image_bytes)
|
15 |
+
width, height = image.size
|
16 |
+
image = image.resize((960, 640))
|
17 |
+
image_array = np.expand_dims(keras.utils.img_to_array(image).astype("float32") / 255.0, axis=0)
|
18 |
+
output = model.predict(image_array)
|
19 |
+
output_image_array = (output[0] * 255.0).clip(0, 255)
|
20 |
+
output_image_array = output_image_array.reshape(
|
21 |
+
(np.shape(output_image_array)[0], np.shape(output_image_array)[1], 3)
|
22 |
+
).astype(np.uint8)
|
23 |
+
output_image = Image.fromarray(output_image_array).resize((width, height))
|
24 |
+
|
25 |
+
if not os.path.exists("user_data"):
|
26 |
+
os.makedirs("user_data")
|
27 |
+
output_image.save("user_data/output.jpg")
|
28 |
+
|
29 |
+
return output_image
|
app/requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy==1.23.5
|
2 |
+
streamlit==1.15.2
|
3 |
+
tensorflow==2.11.0
|
4 |
+
huggingface-hub==0.11.1
|
app/user_data/.gitkeep
ADDED
File without changes
|
setup.cfg
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
[mypy]
|
2 |
+
ignore_missing_imports = True
|
telegram_bot/__init__.py
ADDED
File without changes
|
telegram_bot/bot.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import telebot
|
2 |
+
from PIL import Image
|
3 |
+
import sys
|
4 |
+
import os
|
5 |
+
import io
|
6 |
+
|
7 |
+
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "app"))
|
8 |
+
import model
|
9 |
+
|
10 |
+
bot = telebot.TeleBot("<Paste your token here>")
|
11 |
+
model_instance = model.create_model()
|
12 |
+
|
13 |
+
|
14 |
+
@bot.message_handler(content_types=["photo"])
|
15 |
+
def photo(message):
|
16 |
+
user_id = message.from_user.id
|
17 |
+
file_id = message.photo[-1].file_id
|
18 |
+
file_info = bot.get_file(file_id)
|
19 |
+
downloaded_file = bot.download_file(file_info.file_path)
|
20 |
+
|
21 |
+
if not os.path.exists("user_data"):
|
22 |
+
os.makedirs("user_data")
|
23 |
+
filename = f"user_data/image_{user_id}_{file_id}.jpg"
|
24 |
+
with open(filename, "wb") as new_file:
|
25 |
+
new_file.write(downloaded_file)
|
26 |
+
|
27 |
+
bot.send_message(message.from_user.id, "Изображение обрабатывается...")
|
28 |
+
|
29 |
+
image = Image.open(filename)
|
30 |
+
image_bytes = io.BytesIO()
|
31 |
+
image.save(image_bytes, format=image.format)
|
32 |
+
output_image = model.run_model(image_bytes, model_instance)
|
33 |
+
os.remove(filename)
|
34 |
+
|
35 |
+
bot.send_photo(user_id, output_image)
|
36 |
+
|
37 |
+
|
38 |
+
@bot.message_handler(content_types=["text"])
|
39 |
+
def start(message):
|
40 |
+
bot.send_message(
|
41 |
+
message.from_user.id,
|
42 |
+
"""Этот бот осветляет фотографии, сделанные при плохом освещении, при помощи нейронной сети.\
|
43 |
+
Просто пришлите сюда фото!""",
|
44 |
+
)
|
45 |
+
|
46 |
+
|
47 |
+
bot.polling(none_stop=True, interval=0)
|
telegram_bot/user_data/.gitkeep
ADDED
File without changes
|
test/__init__.py
ADDED
File without changes
|
test/test_images/test1.jpg
ADDED
test/test_images/test2.png
ADDED
test/test_images/test3.jpeg
ADDED
test/test_model.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from PIL import Image
|
2 |
+
import io
|
3 |
+
import os
|
4 |
+
from ..app import model
|
5 |
+
|
6 |
+
model_instance = model.create_model()
|
7 |
+
|
8 |
+
|
9 |
+
def template(filename: str):
|
10 |
+
image = Image.open(filename)
|
11 |
+
width, height = image.size
|
12 |
+
image_bytes = io.BytesIO()
|
13 |
+
image.save(image_bytes, format=image.format)
|
14 |
+
output_image = model.run_model(image_bytes, model_instance)
|
15 |
+
return width, height, output_image
|
16 |
+
|
17 |
+
|
18 |
+
def test_image_jpg():
|
19 |
+
width, height, output_image = template(os.path.join(os.getcwd(), "test/test_images/test1.jpg"))
|
20 |
+
|
21 |
+
assert width == output_image.size[0]
|
22 |
+
assert height == output_image.size[1]
|
23 |
+
|
24 |
+
|
25 |
+
def test_image_png():
|
26 |
+
width, height, output_image = template(os.path.join(os.getcwd(), "test/test_images/test2.png"))
|
27 |
+
|
28 |
+
assert width == output_image.size[0]
|
29 |
+
assert height == output_image.size[1]
|
30 |
+
|
31 |
+
|
32 |
+
def test_image_jpeg():
|
33 |
+
width, height, output_image = template(os.path.join(os.getcwd(), "test/test_images/test3.jpeg"))
|
34 |
+
|
35 |
+
assert width == output_image.size[0]
|
36 |
+
assert height == output_image.size[1]
|