Update app.py
Browse files
app.py
CHANGED
|
@@ -13,15 +13,6 @@ st.markdown(
|
|
| 13 |
<style>
|
| 14 |
.stApp { background-color: #050505 !important; color: white !important; }
|
| 15 |
[data-testid="stSidebar"] { background-color: #000000 !important; border-right: 1px solid #222; }
|
| 16 |
-
|
| 17 |
-
/* Responsive Image Container */
|
| 18 |
-
.img-container {
|
| 19 |
-
display: flex;
|
| 20 |
-
flex-direction: column;
|
| 21 |
-
align-items: center;
|
| 22 |
-
}
|
| 23 |
-
|
| 24 |
-
/* Large Download Button for Mobile */
|
| 25 |
.stDownloadButton button {
|
| 26 |
width: 100%;
|
| 27 |
background-color: #007bff !important;
|
|
@@ -29,79 +20,81 @@ st.markdown(
|
|
| 29 |
padding: 15px;
|
| 30 |
font-weight: bold;
|
| 31 |
}
|
| 32 |
-
|
| 33 |
-
/* Hide Streamlit elements */
|
| 34 |
#MainMenu, footer, .stActionMenu { visibility: hidden !important; }
|
| 35 |
-
img { pointer-events: none; -webkit-user-drag: none; border-radius: 8px; }
|
| 36 |
</style>
|
| 37 |
""",
|
| 38 |
unsafe_allow_html=True
|
| 39 |
)
|
| 40 |
|
| 41 |
-
# ---
|
| 42 |
|
| 43 |
-
def
|
| 44 |
-
|
| 45 |
-
img_array = np.array(image)
|
| 46 |
-
|
| 47 |
-
#
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
def reduce_noise(image):
|
| 54 |
-
"""Removes grain/noise from photos."""
|
| 55 |
img_array = np.array(image)
|
| 56 |
-
# Fast Non-Local Means Denoising
|
| 57 |
denoised = cv2.fastNlMeansDenoisingColored(img_array, None, 10, 10, 7, 21)
|
| 58 |
return Image.fromarray(denoised)
|
| 59 |
|
| 60 |
# --- MAIN APP ---
|
| 61 |
st.title("📸 AI Ultra Enhancer")
|
| 62 |
-
|
| 63 |
uploaded_file = st.file_uploader("Drop an image here", type=["jpg", "png", "jpeg"])
|
| 64 |
|
| 65 |
if uploaded_file:
|
| 66 |
-
# Load and auto-convert
|
| 67 |
original = Image.open(uploaded_file).convert("RGB")
|
| 68 |
|
| 69 |
-
# --- SIDEBAR CONTROLS ---
|
| 70 |
st.sidebar.header("🛠️ Magic Tools")
|
| 71 |
|
| 72 |
-
#
|
| 73 |
-
|
| 74 |
do_denoise = st.sidebar.toggle("Remove Noise (HD)", value=False)
|
| 75 |
|
| 76 |
st.sidebar.divider()
|
| 77 |
|
| 78 |
-
|
| 79 |
-
with st.sidebar.expander("Fine-Tune Adjustments"):
|
| 80 |
br = st.slider("Brightness", 0.5, 2.0, 1.0)
|
| 81 |
ct = st.slider("Contrast", 0.5, 2.0, 1.0)
|
| 82 |
-
sh = st.slider("Sharpness", 0.0,
|
| 83 |
sa = st.slider("Color Pop", 0.0, 2.0, 1.0)
|
| 84 |
|
| 85 |
-
|
| 86 |
-
preset = st.sidebar.radio("Quick Presets", ["Original", "Vibrant", "Cinematic", "B&W", "Sketch"])
|
| 87 |
|
| 88 |
-
# ---
|
| 89 |
processed = original.copy()
|
| 90 |
|
| 91 |
-
# 1.
|
| 92 |
-
if
|
| 93 |
-
processed =
|
| 94 |
if do_denoise:
|
| 95 |
processed = reduce_noise(processed)
|
| 96 |
|
| 97 |
-
# 2.
|
| 98 |
if preset == "Vibrant":
|
| 99 |
processed = ImageEnhance.Color(processed).enhance(1.5)
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
processed = ImageEnhance.
|
| 103 |
-
processed = ImageEnhance.
|
| 104 |
-
processed = ImageEnhance.Color(processed).enhance(0.8)
|
| 105 |
elif preset == "B&W":
|
| 106 |
processed = processed.convert("L").convert("RGB")
|
| 107 |
elif preset == "Sketch":
|
|
@@ -111,7 +104,7 @@ if uploaded_file:
|
|
| 111 |
sketch = cv2.divide(gray, 255 - blur, scale=256)
|
| 112 |
processed = Image.fromarray(sketch).convert("RGB")
|
| 113 |
|
| 114 |
-
# 3.
|
| 115 |
processed = ImageEnhance.Brightness(processed).enhance(br)
|
| 116 |
processed = ImageEnhance.Contrast(processed).enhance(ct)
|
| 117 |
processed = ImageEnhance.Sharpness(processed).enhance(sh)
|
|
@@ -130,9 +123,4 @@ if uploaded_file:
|
|
| 130 |
st.divider()
|
| 131 |
buf = io.BytesIO()
|
| 132 |
processed.save(buf, format="PNG")
|
| 133 |
-
st.download_button(
|
| 134 |
-
"✨ Download Enhanced Image",
|
| 135 |
-
data=buf.getvalue(),
|
| 136 |
-
file_name="AI_Enhanced.png",
|
| 137 |
-
mime="image/png"
|
| 138 |
-
)
|
|
|
|
| 13 |
<style>
|
| 14 |
.stApp { background-color: #050505 !important; color: white !important; }
|
| 15 |
[data-testid="stSidebar"] { background-color: #000000 !important; border-right: 1px solid #222; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
.stDownloadButton button {
|
| 17 |
width: 100%;
|
| 18 |
background-color: #007bff !important;
|
|
|
|
| 20 |
padding: 15px;
|
| 21 |
font-weight: bold;
|
| 22 |
}
|
|
|
|
|
|
|
| 23 |
#MainMenu, footer, .stActionMenu { visibility: hidden !important; }
|
| 24 |
+
img { pointer-events: none; -webkit-user-drag: none; border-radius: 8px; border: 1px solid #333; }
|
| 25 |
</style>
|
| 26 |
""",
|
| 27 |
unsafe_allow_html=True
|
| 28 |
)
|
| 29 |
|
| 30 |
+
# --- THE "FIX" LOGIC (CLAHE + SMART SHARPEN) ---
|
| 31 |
|
| 32 |
+
def smart_enhance(image):
|
| 33 |
+
# Convert PIL to OpenCV BGR
|
| 34 |
+
img_array = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
| 35 |
+
|
| 36 |
+
# 1. CLAHE (Adaptive Equalization) - Fixes the 'blackish' tint issue
|
| 37 |
+
lab = cv2.cvtColor(img_array, cv2.COLOR_BGR2LAB)
|
| 38 |
+
l, a, b = cv2.split(lab)
|
| 39 |
+
|
| 40 |
+
# clipLimit 2.0 keeps it natural; tileGridSize 8x8 is standard
|
| 41 |
+
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
| 42 |
+
cl = clahe.apply(l)
|
| 43 |
+
|
| 44 |
+
limg = cv2.merge((cl,a,b))
|
| 45 |
+
enhanced_bgr = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
|
| 46 |
+
|
| 47 |
+
# 2. Smart Sharpen (Unsharp Mask) - Makes text HD without artifacts
|
| 48 |
+
# We blur a copy and subtract it from the original to find edges
|
| 49 |
+
blurred = cv2.GaussianBlur(enhanced_bgr, (0, 0), 3)
|
| 50 |
+
sharpened = cv2.addWeighted(enhanced_bgr, 1.5, blurred, -0.5, 0)
|
| 51 |
+
|
| 52 |
+
return Image.fromarray(cv2.cvtColor(sharpened, cv2.COLOR_BGR2RGB))
|
| 53 |
|
| 54 |
def reduce_noise(image):
|
|
|
|
| 55 |
img_array = np.array(image)
|
|
|
|
| 56 |
denoised = cv2.fastNlMeansDenoisingColored(img_array, None, 10, 10, 7, 21)
|
| 57 |
return Image.fromarray(denoised)
|
| 58 |
|
| 59 |
# --- MAIN APP ---
|
| 60 |
st.title("📸 AI Ultra Enhancer")
|
|
|
|
| 61 |
uploaded_file = st.file_uploader("Drop an image here", type=["jpg", "png", "jpeg"])
|
| 62 |
|
| 63 |
if uploaded_file:
|
|
|
|
| 64 |
original = Image.open(uploaded_file).convert("RGB")
|
| 65 |
|
|
|
|
| 66 |
st.sidebar.header("🛠️ Magic Tools")
|
| 67 |
|
| 68 |
+
# Use the new Smart Enhance instead of the old Auto-Fix
|
| 69 |
+
do_smart = st.sidebar.toggle("Smart HD Enhancement", value=True)
|
| 70 |
do_denoise = st.sidebar.toggle("Remove Noise (HD)", value=False)
|
| 71 |
|
| 72 |
st.sidebar.divider()
|
| 73 |
|
| 74 |
+
with st.sidebar.expander("Manual Fine-Tune"):
|
|
|
|
| 75 |
br = st.slider("Brightness", 0.5, 2.0, 1.0)
|
| 76 |
ct = st.slider("Contrast", 0.5, 2.0, 1.0)
|
| 77 |
+
sh = st.slider("Manual Sharpness", 0.0, 3.0, 1.0)
|
| 78 |
sa = st.slider("Color Pop", 0.0, 2.0, 1.0)
|
| 79 |
|
| 80 |
+
preset = st.sidebar.radio("Quick Presets", ["Original", "Vibrant", "Document/Text", "B&W", "Sketch"])
|
|
|
|
| 81 |
|
| 82 |
+
# --- PIPELINE ---
|
| 83 |
processed = original.copy()
|
| 84 |
|
| 85 |
+
# 1. AI Logic
|
| 86 |
+
if do_smart:
|
| 87 |
+
processed = smart_enhance(processed)
|
| 88 |
if do_denoise:
|
| 89 |
processed = reduce_noise(processed)
|
| 90 |
|
| 91 |
+
# 2. Preset Logic
|
| 92 |
if preset == "Vibrant":
|
| 93 |
processed = ImageEnhance.Color(processed).enhance(1.5)
|
| 94 |
+
elif preset == "Document/Text":
|
| 95 |
+
# Specifically for screenshots/Allens students notes!
|
| 96 |
+
processed = ImageEnhance.Contrast(processed).enhance(1.5)
|
| 97 |
+
processed = ImageEnhance.Sharpness(processed).enhance(2.0)
|
|
|
|
| 98 |
elif preset == "B&W":
|
| 99 |
processed = processed.convert("L").convert("RGB")
|
| 100 |
elif preset == "Sketch":
|
|
|
|
| 104 |
sketch = cv2.divide(gray, 255 - blur, scale=256)
|
| 105 |
processed = Image.fromarray(sketch).convert("RGB")
|
| 106 |
|
| 107 |
+
# 3. Final Sliders
|
| 108 |
processed = ImageEnhance.Brightness(processed).enhance(br)
|
| 109 |
processed = ImageEnhance.Contrast(processed).enhance(ct)
|
| 110 |
processed = ImageEnhance.Sharpness(processed).enhance(sh)
|
|
|
|
| 123 |
st.divider()
|
| 124 |
buf = io.BytesIO()
|
| 125 |
processed.save(buf, format="PNG")
|
| 126 |
+
st.download_button("✨ Download Enhanced Image", data=buf.getvalue(), file_name="AI_Enhanced.png", mime="image/png")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|