Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/white background #386

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app/1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/Colab.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"authorship_tag":"ABX9TyNzifwmIaQmmM75iyCsAofz"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"},"gpuClass":"standard"},"cells":[{"cell_type":"code","source":["from google.colab import drive\n","drive.mount('/content/drive')\n","\n","!ls /content/drive/"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"yur7vTYv3wxx","executionInfo":{"status":"ok","timestamp":1697182836766,"user_tz":-540,"elapsed":3062,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"dd210930-6f4e-45d2-abea-5c6670236ac0"},"execution_count":11,"outputs":[{"output_type":"stream","name":"stdout","text":["Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount(\"/content/drive\", force_remount=True).\n","MyDrive\n"]}]},{"cell_type":"code","source":["!ls -l /content/drive/MyDrive/"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"48ZCoYhL4BwC","executionInfo":{"status":"ok","timestamp":1697182839001,"user_tz":-540,"elapsed":366,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"77152fc3-1eca-42a7-83b2-fc4ff6bb681d"},"execution_count":12,"outputs":[{"output_type":"stream","name":"stdout","text":["total 1377\n","-rw------- 1 root root 1392695 Aug 18 05:38 a.xlsx\n","drwx------ 2 root root 4096 Feb 20 2022 Classroom\n","drwx------ 4 root root 4096 Oct 13 06:25 DeepL\n","drwx------ 2 root root 4096 Nov 11 2022 RCSC\n","drwx------ 2 root root 4096 Oct 25 2022 SEAGULL\n","-rw------- 1 root root 171 Jul 31 05:35 無題のドキュメント.gdoc\n"]}]},{"cell_type":"code","source":["!ls -l /content/drive/MyDrive/DeepL/Img-Bg-White"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"XOaTC_k34Dzj","executionInfo":{"status":"ok","timestamp":1697182842377,"user_tz":-540,"elapsed":358,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"5f5c3f74-6cc5-4929-afdc-ccae07f23897"},"execution_count":13,"outputs":[{"output_type":"stream","name":"stdout","text":["total 93\n","-rw------- 1 root root 57878 Oct 13 07:35 1.jpg\n","-rw------- 1 root root 0 May 16 04:33 app.py\n","-rw------- 1 root root 147 May 16 04:33 config.py\n","-rw------- 1 root root 8772 May 16 04:33 data_loader.py\n","-rw------- 1 root root 3502 Oct 13 07:40 __init__.py\n","drwx------ 3 root root 4096 Oct 13 06:30 model\n","-rw------- 1 root root 1035 May 16 04:33 README.md\n","-rw------- 1 root root 480 May 16 04:33 requirements.txt\n","drwx------ 3 root root 4096 Oct 13 06:30 saved_models\n","drwx------ 5 root root 4096 Oct 13 06:30 static\n","-rw------- 1 root root 8447 Oct 13 07:36 Untitleaaa.ipynb\n"]}]},{"cell_type":"code","source":["%cd /content/drive/MyDrive/DeepL/Img-Bg-White"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"IwJvGc6y69X1","executionInfo":{"status":"ok","timestamp":1697182845101,"user_tz":-540,"elapsed":2,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"99819aff-14a2-408f-b2fb-ff70d778ee93"},"execution_count":14,"outputs":[{"output_type":"stream","name":"stdout","text":["/content/drive/MyDrive/DeepL/Img-Bg-White\n"]}]},{"cell_type":"code","source":["%run __init__.py"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"SqCHlLVf4Rqp","executionInfo":{"status":"ok","timestamp":1697182856287,"user_tz":-540,"elapsed":7954,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"ca0c975d-1211-489d-9976-43001b43d4a4"},"execution_count":15,"outputs":[{"output_type":"stream","name":"stdout","text":["---Loading Model---\n","---Removing Background...\n","---Success---\n"]}]},{"cell_type":"markdown","source":["THIS ONE WILL NOT WORK"],"metadata":{"id":"iD49WxAW9HDl"}},{"cell_type":"code","source":["%mkdir saved_models\n","%mkdir saved_models/u2net"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"cUpYjA5Q_F3d","executionInfo":{"status":"ok","timestamp":1684214153158,"user_tz":-540,"elapsed":1142,"user":{"displayName":"威廷旼","userId":"02776276979241908427"}},"outputId":"ae8c0e6b-64e4-4151-fbc6-eaf3a4485877"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["mkdir: cannot create directory ‘saved_models’: File exists\n","mkdir: cannot create directory ‘saved_models/u2net’: File exists\n"]}]},{"cell_type":"code","source":["path_proj = '/content/drive/MyDrive/DeepDark/Img-Bg-Remover-Wk'\n","\n","with open(path_proj) as f:\n"],"metadata":{"id":"yUXO0cOX5Jlq"},"execution_count":null,"outputs":[]},{"cell_type":"code","execution_count":null,"metadata":{"id":"GIjR6Rdw3n2a"},"outputs":[],"source":["import torch\n","import torch.nn as nn\n","import torch.optim as optim\n","import numpy as np\n","import cv2\n","import uuid\n","import os\n","\n","from model import U2NET\n","from torch.autograd import Variable\n","from skimage import io, transform\n","from PIL import Image\n","\n","# Get The Current Directory\n","currentDir = os.path.dirname(__file__)\n","\n","# Functions:\n","# Save Results\n","\n","\n","def save_output(image_name, output_name, pred, d_dir, type):\n"," predict = pred\n"," predict = predict.squeeze()\n"," predict_np = predict.cpu().data.numpy()\n"," im = Image.fromarray(predict_np*255).convert('RGB')\n"," image = io.imread(image_name)\n"," imo = im.resize((image.shape[1], image.shape[0]))\n"," pb_np = np.array(imo)\n"," if type == 'image':\n"," # Make and apply mask\n"," mask = pb_np[:, :, 0]\n"," mask = np.expand_dims(mask, axis=2)\n"," imo = np.concatenate((image, mask), axis=2)\n"," imo = Image.fromarray(imo, 'RGBA')\n","\n"," imo.save(d_dir+output_name)\n","# Remove Background From Image (Generate Mask, and Final Results)\n","\n","\n","def removeBg(imagePath):\n"," inputs_dir = os.path.join(currentDir, 'static/inputs/')\n"," results_dir = os.path.join(currentDir, 'static/results/')\n"," masks_dir = os.path.join(currentDir, 'static/masks/')\n","\n"," # convert string of image data to uint8\n"," with open(imagePath, \"rb\") as image:\n"," f = image.read()\n"," img = bytearray(f)\n","\n"," nparr = np.frombuffer(img, np.uint8)\n","\n"," if len(nparr) == 0:\n"," return '---Empty image---'\n","\n"," # decode image\n"," try:\n"," img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)\n"," except:\n"," # build a response dict to send back to client\n"," return \"---Empty image---\"\n","\n"," # save image to inputs\n"," unique_filename = str(uuid.uuid4())\n"," cv2.imwrite(inputs_dir+unique_filename+'.jpg', img)\n","\n"," # processing\n"," image = transform.resize(img, (320, 320), mode='constant')\n","\n"," tmpImg = np.zeros((image.shape[0], image.shape[1], 3))\n","\n"," tmpImg[:, :, 0] = (image[:, :, 0]-0.485)/0.229\n"," tmpImg[:, :, 1] = (image[:, :, 1]-0.456)/0.224\n"," tmpImg[:, :, 2] = (image[:, :, 2]-0.406)/0.225\n","\n"," tmpImg = tmpImg.transpose((2, 0, 1))\n"," tmpImg = np.expand_dims(tmpImg, 0)\n"," image = torch.from_numpy(tmpImg)\n","\n"," image = image.type(torch.FloatTensor)\n"," image = Variable(image)\n","\n"," d1, d2, d3, d4, d5, d6, d7 = net(image)\n"," pred = d1[:, 0, :, :]\n"," ma = torch.max(pred)\n"," mi = torch.min(pred)\n"," dn = (pred-mi)/(ma-mi)\n"," pred = dn\n","\n"," save_output(inputs_dir+unique_filename+'.jpg', unique_filename +\n"," '.png', pred, results_dir, 'image')\n"," save_output(inputs_dir+unique_filename+'.jpg', unique_filename +\n"," '.png', pred, masks_dir, 'mask')\n"," return \"---Success---\"\n","\n","\n","# ------- Load Trained Model --------\n","print(\"---Loading Model---\")\n","model_name = 'u2net'\n","model_dir = os.path.join(currentDir, 'saved_models',\n"," model_name, model_name + '.pth')\n","net = U2NET(3, 1)\n","if torch.cuda.is_available():\n"," net.load_state_dict(torch.load(model_dir))\n"," net.cuda()\n","else:\n"," net.load_state_dict(torch.load(model_dir, map_location='cpu'))\n","# ------- Load Trained Model --------\n","\n","\n","print(\"---Removing Background...\")\n","# ------- Call The removeBg Function --------\n","imgPath = \"1.jpg\" # Change this to your image path\n","print(removeBg(imgPath))\n"]}]}
20 changes: 20 additions & 0 deletions app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Image Background Remover Python Script With U2Net
Remove Backgrounds From Images with u2net Trained model

I was surfing the internet searching for AI tools, and I stumbled upon an Image Background Remover service called Remove.Bg. But I was shocked with the pricing. 0.2$ / Image!

So I decided to take the challenge and build my own Image Background Remover without relying on any APIs or Third Parties.

After Searching for a couple of days, I found a great python project on GitHub, Called U2Net.

A Big Shootout and Thanks to the authors of this project!

I trued my best to make things as simple as possible, so even newbies, can use and run the python script I built.

I created a Short Video Showing The Script & How to use it, and I pointed to two special secrets that may help you build an online income stream with the help of this script. here is the video:
https://youtu.be/KkhPN7Z4Fy8

Download The Project Source Code With Trainined Model Here:
https://hasanaboulhasan.com/python-image-background-remover/

Thank You!
116 changes: 116 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import cv2
import uuid
import os

from model import U2NET
from torch.autograd import Variable
from skimage import io, transform
from PIL import Image

# Get The Current Directory
currentDir = os.path.dirname(__file__)

# Functions:
# Save Results


def save_output(image_name, output_name, pred, d_dir, type):
predict = pred
predict = predict.squeeze()
predict_np = predict.cpu().data.numpy()
im = Image.fromarray(predict_np*255).convert('RGB')
image = io.imread(image_name)
imo = im.resize((image.shape[1], image.shape[0]))
pb_np = np.array(imo)
if type == 'image':
# Make and apply mask
mask = pb_np[:, :, 0]
mask = np.expand_dims(mask, axis=2)
imo = np.concatenate((image, mask), axis=2)
imo = Image.fromarray(imo, 'RGBA')

image = imo.convert("RGBA")
new_image = Image.new("RGBA", image.size, "WHITE") # Create a white rgba background
new_image.paste(image, (0, 0), image) # Paste the image on the background. Go to the links given below for details.
new_image.convert('RGB').save(d_dir+output_name)
# Remove Background From Image (Generate Mask, and Final Results)


def removeBg(imagePath):
inputs_dir = os.path.join(currentDir, 'static/inputs/')
results_dir = os.path.join(currentDir, 'static/results/')
masks_dir = os.path.join(currentDir, 'static/masks/')

# convert string of image data to uint8
with open(imagePath, "rb") as image:
f = image.read()
img = bytearray(f)

nparr = np.frombuffer(img, np.uint8)

if len(nparr) == 0:
return '---Empty image---'

# decode image
try:
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
except:
# build a response dict to send back to client
return "---Empty image---"

# save image to inputs
unique_filename = str(uuid.uuid4())
cv2.imwrite(inputs_dir+unique_filename+'.jpg', img)

# processing
image = transform.resize(img, (320, 320), mode='constant')

tmpImg = np.zeros((image.shape[0], image.shape[1], 3))

tmpImg[:, :, 0] = (image[:, :, 0]-0.485)/0.229
tmpImg[:, :, 1] = (image[:, :, 1]-0.456)/0.224
tmpImg[:, :, 2] = (image[:, :, 2]-0.406)/0.225

tmpImg = tmpImg.transpose((2, 0, 1))
tmpImg = np.expand_dims(tmpImg, 0)
image = torch.from_numpy(tmpImg)

image = image.type(torch.FloatTensor)
image = Variable(image)

d1, d2, d3, d4, d5, d6, d7 = net(image)
pred = d1[:, 0, :, :]
ma = torch.max(pred)
mi = torch.min(pred)
dn = (pred-mi)/(ma-mi)
pred = dn

save_output(inputs_dir+unique_filename+'.jpg', unique_filename +
'.png', pred, results_dir, 'image')
save_output(inputs_dir+unique_filename+'.jpg', unique_filename +
'.png', pred, masks_dir, 'mask')
return "---Success---"


# ------- Load Trained Model --------
print("---Loading Model---")
model_name = 'u2net'
model_dir = os.path.join(currentDir, 'saved_models',
model_name, model_name + '.pth')
net = U2NET(3, 1)
if torch.cuda.is_available():
net.load_state_dict(torch.load(model_dir))
net.cuda()
else:
net.load_state_dict(torch.load(model_dir, map_location='cpu'))
# ------- Load Trained Model --------


print("---Removing Background...")
# ------- Call The removeBg Function --------
imgPath = "1.jpg" # Change this to your image path
print(removeBg(imgPath))
Empty file added app/app.py
Empty file.
8 changes: 8 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import json

with open('/etc/config.json') as config_file:
config = json.load(config_file)

class Config:
SECRET_KEY = config.get('SECRET_KEY')

Loading