Skip to content

Instantly share code, notes, and snippets.

@nakasyou
Created March 30, 2024 03:23
Show Gist options
  • Save nakasyou/3cb65009db1061e703411778c157ca3f to your computer and use it in GitHub Desktop.
Save nakasyou/3cb65009db1061e703411778c157ca3f to your computer and use it in GitHub Desktop.
透かし削除
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"mount_file_id": "1bNFzbhfEIaFmeDsGHVzwsfyOWEOl_udl",
"authorship_tag": "ABX9TyOThcQTEY1rGOB3Edx/aiTp",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/nakasyou/3cb65009db1061e703411778c157ca3f/.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"source": [
"# はいチーズ!の透かしを消すやつ\n",
"[はいチーズ!](http://8122.jp/)というサイトの透かしを消すプログラムです。\n",
"\n",
"## 使い方\n",
"まず、スクレイピングか何かをして、画像を入手します。\n",
"\n",
"透かしをずらした2つの画像は、`0-a.png`、`0-b.png`のように、`{連番}-[a|b].png`としてください。\n",
"\n",
"そして、それを`data`ディレクトリに入れて、連番の数を最後のコードの変数`n`に入れたらできます。\n",
"\n",
"## 仕組み\n",
"画像をy方向に分割して、透かしをずらした2ファイルの部分を照らし合わせます。\n",
"ソーベルフィルターをかけてその平均を出し、平均が少ない方が透かしがないブロックのはずなので少ない方を選択して結合、出力します。\n",
"\n",
"## 注意\n",
"使用は自己責任でお願いします。\n",
"\n",
"## ライセンス\n",
"```\n",
"MIT License\n",
"\n",
"Copyright (c) 2024 Shotaro Nakamura\n",
"\n",
"Permission is hereby granted, free of charge, to any person obtaining a copy\n",
"of this software and associated documentation files (the \"Software\"), to deal\n",
"in the Software without restriction, including without limitation the rights\n",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n",
"copies of the Software, and to permit persons to whom the Software is\n",
"furnished to do so, subject to the following conditions:\n",
"\n",
"The above copyright notice and this permission notice shall be included in all\n",
"copies or substantial portions of the Software.\n",
"\n",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n",
"SOFTWARE.\n",
"```"
],
"metadata": {
"id": "7tX31AbjXMm7"
}
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"id": "XBMYU4DPb_w8",
"cellView": "form"
},
"outputs": [],
"source": [
"#@title ライブラリの`import`\n",
"from PIL import Image\n",
"import numpy as np\n",
"import random\n",
"from IPython.display import Image as DisplayImage\n",
"from tqdm import tqdm\n",
"import cv2\n",
"import json"
]
},
{
"cell_type": "code",
"source": [
"#@title 出力ディレクトリを作成\n",
"!mkdir dist"
],
"metadata": {
"id": "gtHTu_t3VvSK",
"cellView": "form"
},
"execution_count": 3,
"outputs": []
},
{
"cell_type": "code",
"source": [
"#@title Pillowをノートブックに出力する関数\n",
"def display_pil(im):\n",
" im.save('/tmp/im.png')\n",
" display(DisplayImage(filename='/tmp/im.png'))"
],
"metadata": {
"id": "Y7XhgOcucOi1",
"cellView": "form"
},
"execution_count": 4,
"outputs": []
},
{
"cell_type": "code",
"source": [
"#@title ソーベルフィルター(ChatGPTに感謝)\n",
"def sobel(img_arr):\n",
" cv2_image = cv2.cvtColor(img_arr, cv2.COLOR_RGB2BGR)\n",
" gray_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY)\n",
" sobel_x = cv2.Sobel(gray_image, cv2.CV_64F, 1, 0, ksize=3)\n",
" sobel_y = cv2.Sobel(gray_image, cv2.CV_64F, 0, 1, ksize=3)\n",
" sobel_combined = cv2.magnitude(sobel_x, sobel_y)\n",
" return sobel_combined"
],
"metadata": {
"id": "umsLrdcWhD-Z",
"cellView": "form"
},
"execution_count": 5,
"outputs": []
},
{
"cell_type": "code",
"source": [
"#@title 透かしを消す関数\n",
"def clear(image_a, image_b, step):\n",
" arr_a = np.array(image_a)\n",
" arr_b = np.array(image_b)\n",
"\n",
" result = []\n",
" for start_y in range(0, len(arr_a), step):\n",
" piece_a = arr_a[start_y:start_y+step]\n",
" piece_b = arr_b[start_y:start_y+step]\n",
" mean_a = np.mean(sobel(piece_a))\n",
" mean_b = np.mean(sobel(piece_b))\n",
"\n",
" #Image.fromarray(arr)\n",
" #display_pil(im)\n",
" result.append(piece_a if mean_a < mean_b else piece_b)\n",
"\n",
" \"\"\"display_pil(Image.fromarray(piece_a))\n",
" print(mean_a)\n",
" display_pil(Image.fromarray(piece_b))\n",
" print(mean_b)\n",
" print()\"\"\"\n",
" result = np.vstack(result)\n",
"\n",
" return Image.fromarray(result)\n"
],
"metadata": {
"id": "4MmqdxTDa7XC",
"cellView": "form"
},
"execution_count": 6,
"outputs": []
},
{
"cell_type": "code",
"source": [
"n = 10 # 画像の数\n",
"for i in tqdm(range(n)):\n",
" image_a = Image.open(f\"data/{i}-a.png\").convert(\"RGB\")\n",
" image_b = Image.open(f\"data/{i}-b.png\").convert(\"RGB\")\n",
"\n",
" result = clear(image_a, image_b, 10)\n",
" result = clear(image_a, result, 50)\n",
" result = clear(image_b, result, 50)\n",
" result = clear(image_a, result, 100)\n",
" result = clear(image_b, result, 100)\n",
"\n",
" result.save(f'dist/{i}.png')\n",
" #display(DisplayImage(filename=f'dist/{i}.png'))\n"
],
"metadata": {
"id": "8AIpKCKSOWc5"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"#@title `dist`を`dist.zip`に\n",
"!zip -r dist.zip dist"
],
"metadata": {
"id": "MJktF_uprSLA",
"cellView": "form"
},
"execution_count": null,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment