├── requirements.txt
├── Sample Images for Testing
├── meadow-5648849_1280.jpg
├── nature-6722031_1280.jpg
├── mountains-7662717_1280.jpg
├── mountains-8292685_1280.jpg
└── ai-generated-9025430_1280.jpg
├── README.md
├── Contribution Guide
└── contribution.md
└── DeFogify_Main.py
/requirements.txt:
--------------------------------------------------------------------------------
1 | opencv-python
2 | gradio
3 | numpy
4 |
--------------------------------------------------------------------------------
/Sample Images for Testing/meadow-5648849_1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitgoap/DeFogify/HEAD/Sample Images for Testing/meadow-5648849_1280.jpg
--------------------------------------------------------------------------------
/Sample Images for Testing/nature-6722031_1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitgoap/DeFogify/HEAD/Sample Images for Testing/nature-6722031_1280.jpg
--------------------------------------------------------------------------------
/Sample Images for Testing/mountains-7662717_1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitgoap/DeFogify/HEAD/Sample Images for Testing/mountains-7662717_1280.jpg
--------------------------------------------------------------------------------
/Sample Images for Testing/mountains-8292685_1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitgoap/DeFogify/HEAD/Sample Images for Testing/mountains-8292685_1280.jpg
--------------------------------------------------------------------------------
/Sample Images for Testing/ai-generated-9025430_1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitgoap/DeFogify/HEAD/Sample Images for Testing/ai-generated-9025430_1280.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 |
3 | This project implements a single-image haze removal technique using the Dark Channel Prior, as described in the research paper: ``Single Image Haze Removal Using Dark Channel Prior``
4 | The dehazing algorithm is designed to enhance the quality of images affected by haze. This method is effective for various applications in image processing where haze reduction is required.
5 |
6 | ## [Research Paper](https://ieeexplore.ieee.org/document/5567108)
7 |
8 | ## Introduction
9 |
10 | Haze removal is essential for enhancing image clarity and visibility in outdoor scenes, improving the performance of vision-based applications.
11 |
12 | ## Features
13 |
14 | - **Single Image Dehazing**
15 | Process one image at a time to remove haze and bring out hidden details using the Dark Channel Prior.
16 | - **Bulk Image Dehazing**
17 | Process multiple images simultaneously. This feature is perfect for efficiently dehazing an entire batch of images.
18 | - **Video Dehazing**
19 | Dehaze video files by processing each frame individually to ensure a clear and detailed output even for moving visual content.
20 |
21 |
22 |
23 |
24 |
25 | ### Before and After Examples
26 |
27 | | Original Image | Dehazed Image |
28 | |----------------|---------------|
29 | |
|
|
30 | |
|
|
31 | |
|
|
32 |
33 | ## Live Demo
34 |
35 | Try the dehazing app live at ``Hugging Face``:
36 |
37 | [Visit DeFogify in 🤗 space](https://huggingface.co/spaces/MLap/deFogify)
38 |
39 | ## Installation
40 |
41 | Ensure you have the required Python packages installed. Dependencies are listed in the `requirements.txt` file.
42 |
43 | To install the required packages, use:
44 |
45 | ```bash
46 | pip install -r requirements.txt
47 | ```
48 |
49 | For Ubuntu/Debian-based systems, also install:
50 |
51 | ```bash
52 | sudo apt-get update
53 | sudo apt-get install libgl1-mesa-glx
54 | ```
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Contribution Guide/contribution.md:
--------------------------------------------------------------------------------
1 | # Contributing To DeFogify
2 |
3 | This documentation guides you in the contribution process.
4 |
5 | ## Submitting Contributions👩💻
6 |
7 |
8 | ### 1️⃣ Fork the project
9 |
10 | [Fork](https://github.com/gitgoap/DeFogify/fork) the repository, this creates a copy of the repository under your GitHub profile for working:
11 | ```bash
12 | # clone your fork locally
13 | git clone https://github.com//DeFogify
14 | cd DeFogify
15 |
16 | # add the original repository as 'upstream' remote
17 | git remote add upstream https://github.com/original-owner/DeFogify
18 | ```
19 |
20 | If you have already forked the project, just update your fork:
21 | ```bash
22 | # Fetch and merge the latest updates from upstream
23 | git pull upstream main
24 | git checkout main
25 | git merge upstream/main
26 | git push origin main
27 | ```
28 |
29 | Create a new branch before working on a new issue:
30 | ```bash
31 | git checkoout -b
32 | ```
33 |
34 | ### 2️⃣ Work on feature/fixes
35 |
36 | - Follow the [Installation instruction](https://github.com/gitgoap/DeFogify#installation) to set up your environment.
37 | - Implement the features/fixes.
38 | - After you are done making changes, add the files to git:
39 | ```bash
40 | # To add all new files to the working branch.
41 | git add .
42 | # To add files selectively to the working branch
43 | git file1 file2 file3
44 | ```
45 |
46 | ### 3️⃣ Commit
47 |
48 | commit the changes with:
49 | ```bash
50 | # This message gets associated with every file in your commit
51 | git commit -m "descriptive message"
52 | ```
53 | Add a descriptive message for convenience of the reviewer.
54 |
55 | **Note:** Squash multiple commits into one for a clean pull request.
56 |
57 | ### 4️⃣ Push Changes
58 |
59 | Upload your changes to your fork from local:
60 | ```bash
61 | git push -u origin branch_name
62 | ```
63 |
64 | ### 5️⃣ Pull Request
65 |
66 | - Create a Pull Request from your fork
67 | `Contribute` -> `Open Pull Request`
68 | which will be reviewed and suggestions for improvements.
69 | - Provide a clear title and description linking the associated issue, helps reviewers know context of the Pull Request.
70 |
71 | > Your Pull Request will be reviewed and merged by the maintainer 🚀
72 |
73 | ## Need Help?🤔
74 | You can refer to the following articles on the basics of Git and GitHub and also contact the Project Mentors, in case you are stuck:
75 |
76 | - [Watch this video to get started, if you have no clue about open source](https://youtu.be/SYtPC9tHYyQ)
77 | - [Forking a Repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
78 | - [Cloning a Repo](https://help.github.com/en/desktop/contributing-to-projects/creating-a-pull-request)
79 | - [How to create a Pull Request](https://opensource.com/article/19/7/create-pull-request-github)
80 | - [Getting started with Git and GitHub](https://towardsdatascience.com/getting-started-with-git-and-github-6fcd0f2d4ac6)
81 | - [GitHub Desktop]([Getting started with GitHub Desktop - GitHub Docs](https://docs.github.com/en/desktop/overview/getting-started-with-github-desktop))
82 | - [Learn GitHub from Scratch](https://lab.github.com/githubtraining/introduction-to-github)
83 |
84 | Hope you will learn something new while contributing to this project!!
85 |
86 |
87 |
--------------------------------------------------------------------------------
/DeFogify_Main.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 | import gradio as gr
4 | import tempfile
5 | import os
6 | from tqdm import tqdm
7 |
8 | # Original Functions
9 | def dark_channel(img, size=15):
10 | r, g, b = cv2.split(img)
11 | min_img = cv2.min(r, cv2.min(g, b))
12 | kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (size, size))
13 | dc_img = cv2.erode(min_img, kernel)
14 | return dc_img
15 |
16 | def get_atmo(img, percent=0.001):
17 | mean_perpix = np.mean(img, axis=2).reshape(-1)
18 | mean_topper = mean_perpix[:int(img.shape[0] * img.shape[1] * percent)]
19 | return np.mean(mean_topper)
20 |
21 | def get_trans(img, atom, w=0.95):
22 | x = img / atom
23 | t = 1 - w * dark_channel(x, 15)
24 | return t
25 |
26 | def guided_filter(p, i, r, e):
27 | mean_I = cv2.boxFilter(i, cv2.CV_64F, (r, r))
28 | mean_p = cv2.boxFilter(p, cv2.CV_64F, (r, r))
29 | corr_I = cv2.boxFilter(i * i, cv2.CV_64F, (r, r))
30 | corr_Ip = cv2.boxFilter(i * p, cv2.CV_64F, (r, r))
31 | var_I = corr_I - mean_I * mean_I
32 | cov_Ip = corr_Ip - mean_I * mean_p
33 | a = cov_Ip / (var_I + e)
34 | b = mean_p - a * mean_I
35 | mean_a = cv2.boxFilter(a, cv2.CV_64F, (r, r))
36 | mean_b = cv2.boxFilter(b, cv2.CV_64F, (r, r))
37 | q = mean_a * i + mean_b
38 | return q
39 |
40 | def dehaze(image):
41 | img = image.astype('float64') / 255
42 | img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).astype('float64') / 255
43 | atom = get_atmo(img)
44 | trans = get_trans(img, atom)
45 | trans_guided = guided_filter(trans, img_gray, 20, 0.0001)
46 | trans_guided = np.maximum(trans_guided, 0.25) # Ensure trans_guided is not below 0.25
47 | result = np.empty_like(img)
48 | for i in range(3):
49 | result[:, :, i] = (img[:, :, i] - atom) / trans_guided + atom
50 | result = np.clip(result, 0, 1)
51 | return (result * 255).astype(np.uint8)
52 |
53 | # Single Image Processing
54 | def process_single_image(image):
55 | dehazed_img = dehaze(image)
56 | return dehazed_img
57 |
58 | # Batch Processing Function for Multiple Images with Progress Bar
59 | def process_images(files):
60 | temp_dir = tempfile.mkdtemp()
61 | output_files = []
62 |
63 | for file in tqdm(files, desc="Processing Images"):
64 | img = cv2.imread(file.name)
65 | if img is not None:
66 | dehazed_img = dehaze(img)
67 | output_path = os.path.join(temp_dir, os.path.basename(file.name))
68 | cv2.imwrite(output_path, dehazed_img)
69 | output_files.append(output_path)
70 |
71 | return output_files
72 |
73 | # Video Dehazing Function with Gradio Progress Bar and Error Handling
74 | def dehaze_video(input_video_path, output_video_path, progress=None):
75 | try:
76 | cap = cv2.VideoCapture(input_video_path)
77 | if not cap.isOpened():
78 | raise ValueError("Error: Could not open video.")
79 |
80 | fourcc = cv2.VideoWriter_fourcc(*'mp4v')
81 | fps = int(cap.get(cv2.CAP_PROP_FPS))
82 | frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
83 | frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
84 | total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
85 |
86 | if total_frames <= 0: # Assume a constant count for webcam scenarios
87 | total_frames = 1000
88 |
89 | out = cv2.VideoWriter(output_video_path, fourcc, fps, (frame_width, frame_height))
90 | frame_count = 0
91 |
92 | if progress is not None:
93 | progress(0, desc="Processing Video", unit="frame")
94 |
95 | while cap.isOpened():
96 | ret, frame = cap.read()
97 | if not ret:
98 | break
99 | dehazed_frame = dehaze(frame)
100 | out.write(dehazed_frame)
101 | frame_count += 1
102 |
103 | if progress is not None:
104 | progress(frame_count / total_frames) # Ensure progress is within 0-1 range
105 |
106 | cap.release()
107 | out.release()
108 | print(f"\nDehazed video saved to: {output_video_path}")
109 | except Exception as e:
110 | print(f"An error occurred during video processing: {e}")
111 |
112 | # Gradio Video Processing Wrapper
113 | def process_video(file):
114 | input_video_path = file # File is a string representing the path
115 | output_video_path = os.path.join(tempfile.mkdtemp(), "dehazed_video.mp4")
116 | progress = gr.Progress()
117 | dehaze_video(input_video_path, output_video_path, progress)
118 | return output_video_path
119 |
120 | # Real-Time Webcam Processing with Gradio Progress Bar
121 | def dehaze_webcam(progress=gr.Progress()):
122 | try:
123 | cap = cv2.VideoCapture(0) # Capture from the first webcam
124 | if not cap.isOpened():
125 | raise ValueError("Unable to open webcam")
126 |
127 | frame_count = 0
128 | total_frames = 100 # Arbitrary number for progress bar
129 | progress(0, desc="Processing Webcam Feed", unit="frame")
130 |
131 | while frame_count < total_frames:
132 | ret, frame = cap.read()
133 | if not ret:
134 | break
135 | dehazed_frame = dehaze(frame)
136 | frame_count += 1
137 | progress(frame_count / total_frames) # Ensure progress is within 0-1 range
138 |
139 | cv2.imshow('Dehazed Webcam Feed', dehazed_frame)
140 | if cv2.waitKey(1) & 0xFF == ord('q'):
141 | break
142 |
143 | cap.release()
144 | cv2.destroyAllWindows()
145 | progress(1) # Ensure progress bar reaches 100%
146 | except Exception as e:
147 | print(f"An error occurred during webcam processing: {e}")
148 |
149 | # Gradio Webcam Processing Wrapper
150 | def process_webcam():
151 | progress = gr.Progress()
152 | dehaze_webcam(progress)
153 | return "Webcam processing completed."
154 |
155 | # Example Images for Testing
156 | example_images = [
157 | "Sample Images for Testing/ai-generated-9025430_1280.jpg",
158 | "Sample Images for Testing/meadow-5648849_1280.jpg",
159 | "Sample Images for Testing/mountains-7662717_1280.jpg",
160 | "Sample Images for Testing/nature-6722031_1280.jpg"
161 | ]
162 |
163 | example_paths = []
164 | for i, img_path in enumerate(example_images):
165 | img = cv2.imread(img_path)
166 | save_path = f"example_image_{i+1}.png"
167 | cv2.imwrite(save_path, img)
168 | example_paths.append([save_path])
169 |
170 | # Gradio Interfaces
171 | PixelDehazer = gr.Interface(
172 | fn=process_single_image,
173 | inputs=gr.Image(type="numpy"),
174 | outputs="image",
175 | examples=example_paths,
176 | cache_examples=False,
177 | description="Upload a single image to remove haze."
178 | )
179 |
180 | BatchDehazer = gr.Interface(
181 | fn=process_images,
182 | inputs=gr.Files(label="Upload Multiple Images", file_types=["image"]),
183 | outputs=gr.Files(label="Download Dehazed Images"),
184 | description="Upload multiple images to remove haze. Download the processed dehazed images."
185 | )
186 |
187 | VideoDehazer = gr.Interface(
188 | fn=process_video,
189 | inputs=gr.Video(label="Upload a Video"),
190 | outputs=gr.File(label="Download Dehazed Video"),
191 | description="Upload a video to remove haze. Download the processed dehazed video."
192 | )
193 |
194 | # Combined Gradio App
195 | app = gr.TabbedInterface(
196 | [PixelDehazer, BatchDehazer, VideoDehazer],
197 | ["Single Image Dehazing", "Batch Image Dehazing", "Video Dehazing"],
198 | title="DeFogify App"
199 | )
200 |
201 | # Launch the Gradio App
202 | if __name__ == "__main__":
203 | app.launch()
204 |
--------------------------------------------------------------------------------