Danila Pechenev commited on
Commit
33fdf43
2 Parent(s): fa592d3 e6f0240

Merge pull request #1 from Danila-Pechenev/app

Browse files
.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]