{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        pass\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-10-08T23:05:17.64341Z","iopub.execute_input":"2023-10-08T23:05:17.644867Z","iopub.status.idle":"2023-10-08T23:05:18.083742Z","shell.execute_reply.started":"2023-10-08T23:05:17.644814Z","shell.execute_reply":"2023-10-08T23:05:18.0825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Process large images\nThis notebook will\n\n1. Take one large gigapixel images frpm `train_images` directory and break them into smaller patches of size 1024\n2. Remove the patches that are mostly empty (mostly at the edges) as these do not contain any useful information\n3. If you have a computer with multiple cores using golang will have much lesser overhead than python multiprocessing library and gives approximately 50-60x speedup\n\nWill share more code on preprocessing.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!go --version\n# \n!wget https://go.dev/dl/go1.21.2.linux-amd64.tar.gz\n# Note that this cannot be done during test time","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" !rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.2.linux-amd64.tar.gz","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ['PATH'] += \":/usr/local/go/bin\"","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:05:32.027636Z","iopub.execute_input":"2023-10-08T23:05:32.028145Z","iopub.status.idle":"2023-10-08T23:05:32.036326Z","shell.execute_reply.started":"2023-10-08T23:05:32.028107Z","shell.execute_reply":"2023-10-08T23:05:32.034374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" !echo $PATH","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:05:21.275603Z","iopub.execute_input":"2023-10-08T23:05:21.277439Z","iopub.status.idle":"2023-10-08T23:05:22.401415Z","shell.execute_reply.started":"2023-10-08T23:05:21.277368Z","shell.execute_reply":"2023-10-08T23:05:22.400027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir /data/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile tileimage.go\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"image/jpeg\"\n\t\"image/png\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// cropAndSave crops the image based on provided coordinates and saves to the specified folder.\nfunc cropAndSave(img image.Image, x, y, d int, filename, dirOut string) {\n\trect := image.Rect(x, y, x+d, y+d)\n\tsubImg := img.(interface {\n\t\tSubImage(r image.Rectangle) image.Image\n\t}).SubImage(rect)\n\t\n\toutPath := filepath.Join(dirOut, fmt.Sprintf(\"%s_%d_%d%s\", strings.TrimSuffix(filename, filepath.Ext(filename)), y, x, filepath.Ext(filename)))\n\toutFile, err := os.Create(outPath)\n\tif err != nil {\n\t\tfmt.Println(\"Error creating file:\", err)\n\t\treturn\n\t}\n\tdefer outFile.Close()\n\n\tif filepath.Ext(filename) == \".jpg\" || filepath.Ext(filename) == \".jpeg\" {\n\t\tjpeg.Encode(outFile, subImg, nil)\n\t} else if filepath.Ext(filename) == \".png\" {\n\t\tpng.Encode(outFile, subImg)\n\t}\n}\n\nfunc main() {\n\tfilename := \"1080.png\" // Change this to your image file here\n\tdirIn := \"/kaggle/input/UBC-OCEAN/train_images/\"\n\tdirOut := \"/data/\"\n\td := 1024  // desired width of each output image\n\n\timgFile, err := os.Open(filepath.Join(dirIn, filename))\n\tif err != nil {\n\t\tfmt.Println(\"Error opening image:\", err)\n\t\treturn\n\t}\n\tdefer imgFile.Close()\n\n\timg, _, err := image.Decode(imgFile)\n\tif err != nil {\n\t\tfmt.Println(\"Error decoding image:\", err)\n\t\treturn\n\t}\n\n\tbounds := img.Bounds()\n\twidth, height := bounds.Max.X, bounds.Max.Y\n\n\tvar wg sync.WaitGroup\n\tfor y := 0; y <= height-d; y += d {\n\t\tfor x := 0; x <= width-d; x += d {\n\t\t\twg.Add(1)\n\t\t\tgo func(x, y int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tcropAndSave(img, x, y, d, filename, dirOut)\n\t\t\t}(x, y)\n\t\t}\n\t}\n\n\twg.Wait()\n}\n","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:06:21.077891Z","iopub.execute_input":"2023-10-08T23:06:21.078368Z","iopub.status.idle":"2023-10-08T23:06:21.088736Z","shell.execute_reply.started":"2023-10-08T23:06:21.078325Z","shell.execute_reply":"2023-10-08T23:06:21.087106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %env GOMAXPROCS=32\n# Change this to the number of CPU cores in your computer\n# You can get this by os.cpu_count()","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:07:55.837803Z","iopub.execute_input":"2023-10-08T23:07:55.83842Z","iopub.status.idle":"2023-10-08T23:07:55.845151Z","shell.execute_reply.started":"2023-10-08T23:07:55.838373Z","shell.execute_reply":"2023-10-08T23:07:55.843372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n!go run tileimage.go","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:06:22.072768Z","iopub.execute_input":"2023-10-08T23:06:22.073154Z","iopub.status.idle":"2023-10-08T23:07:48.451739Z","shell.execute_reply.started":"2023-10-08T23:06:22.073124Z","shell.execute_reply":"2023-10-08T23:07:48.450023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls /data/","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:07:57.542526Z","iopub.execute_input":"2023-10-08T23:07:57.543073Z","iopub.status.idle":"2023-10-08T23:07:58.690971Z","shell.execute_reply.started":"2023-10-08T23:07:57.543007Z","shell.execute_reply":"2023-10-08T23:07:58.689401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:08:24.155582Z","iopub.execute_input":"2023-10-08T23:08:24.159055Z","iopub.status.idle":"2023-10-08T23:08:24.175922Z","shell.execute_reply.started":"2023-10-08T23:08:24.15882Z","shell.execute_reply":"2023-10-08T23:08:24.173318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:08:36.19885Z","iopub.execute_input":"2023-10-08T23:08:36.19958Z","iopub.status.idle":"2023-10-08T23:08:36.206951Z","shell.execute_reply.started":"2023-10-08T23:08:36.199529Z","shell.execute_reply":"2023-10-08T23:08:36.205264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img = Image.open(\"/data/1080_5120_9216.png\")","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:09:24.903115Z","iopub.execute_input":"2023-10-08T23:09:24.903496Z","iopub.status.idle":"2023-10-08T23:09:24.908876Z","shell.execute_reply.started":"2023-10-08T23:09:24.903468Z","shell.execute_reply":"2023-10-08T23:09:24.907624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:09:25.926418Z","iopub.execute_input":"2023-10-08T23:09:25.926794Z","iopub.status.idle":"2023-10-08T23:09:26.066218Z","shell.execute_reply.started":"2023-10-08T23:09:25.926765Z","shell.execute_reply":"2023-10-08T23:09:26.065167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# You can find a lot of black images. These are useless and will consume space","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:09:59.208106Z","iopub.execute_input":"2023-10-08T23:09:59.208479Z","iopub.status.idle":"2023-10-08T23:09:59.21412Z","shell.execute_reply.started":"2023-10-08T23:09:59.208451Z","shell.execute_reply":"2023-10-08T23:09:59.213081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Remove useless tiles which are mostly black","metadata":{}},{"cell_type":"code","source":"%%writefile remove_empty.go \n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\n\t// \"image/color\"\n\t_ \"image/jpeg\"\n\t_ \"image/png\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n)\n\n// Checks if the image is almost black\nfunc isAlmostBlack(img image.Image) bool {\n\tthreshold := 3 // Adjust this threshold as needed\n\ttotalPixels := 0\n\tdarkPixels := 0\n\n\tbounds := img.Bounds()\n\tfor y := bounds.Min.Y; y < bounds.Max.Y; y++ {\n\t\tfor x := bounds.Min.X; x < bounds.Max.X; x++ {\n\t\t\tr, g, b, _ := img.At(x, y).RGBA()\n\t\t\t// Check if the pixel is dark\n\t\t\tif int(r) < int(threshold) && int(g) < int(threshold) && int(b) < int(threshold) {\n\t\t\t\tdarkPixels++\n\t\t\t}\n\t\t\ttotalPixels++\n\t\t}\n\t}\n\t// Adjust this ratio as needed. For now, it considers the image as \"almost black\" if 90% of the pixels are dark.\n\treturn float64(darkPixels)/float64(totalPixels) > 0.99\n}\n\n// Processes the image\nfunc processImage(filename string) {\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\tfmt.Printf(\"Error opening file %s: %v\\n\", filename, err)\n\t\treturn\n\t}\n\tdefer file.Close()\n\n\timg, _, err := image.Decode(file)\n\tif err != nil {\n\t\tfmt.Printf(\"Error decoding image %s: %v\\n\", filename, err)\n\t\treturn\n\t}\n\n\tif isAlmostBlack(img) {\n\t\terr := os.Remove(filename)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Error deleting file %s: %v\\n\", filename, err)\n\t\t} else {\n\t\t\tfmt.Printf(\"Deleted almost black image: %s\\n\", filename)\n\t\t}\n\t}\n}\n\nfunc main() {\n\tdir := \"/data/\" // Change this to your directory\n\n\tfiles, err := ioutil.ReadDir(dir)\n\tif err != nil {\n\t\tfmt.Println(\"Error reading directory:\", err)\n\t\treturn\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, f := range files {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\text := filepath.Ext(f.Name())\n\t\tif ext == \".jpg\" || ext == \".png\" { // You can add more extensions if needed\n\t\t\twg.Add(1)\n\t\t\tgo func(filename string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tprocessImage(filename)\n\t\t\t}(filepath.Join(dir, f.Name()))\n\t\t}\n\t}\n\twg.Wait()\n}\n","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:11:23.393917Z","iopub.execute_input":"2023-10-08T23:11:23.394441Z","iopub.status.idle":"2023-10-08T23:11:23.405413Z","shell.execute_reply.started":"2023-10-08T23:11:23.394395Z","shell.execute_reply":"2023-10-08T23:11:23.404078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!go run remove_empty.go","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:11:31.22473Z","iopub.execute_input":"2023-10-08T23:11:31.225209Z","iopub.status.idle":"2023-10-08T23:12:03.033101Z","shell.execute_reply.started":"2023-10-08T23:11:31.225173Z","shell.execute_reply":"2023-10-08T23:12:03.028819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls /data/","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:12:03.039357Z","iopub.execute_input":"2023-10-08T23:12:03.039972Z","iopub.status.idle":"2023-10-08T23:12:04.763631Z","shell.execute_reply.started":"2023-10-08T23:12:03.039919Z","shell.execute_reply":"2023-10-08T23:12:04.762036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img = Image.open(\"/data/1080_15360_8192.png\")","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:12:34.701513Z","iopub.execute_input":"2023-10-08T23:12:34.701956Z","iopub.status.idle":"2023-10-08T23:12:34.709473Z","shell.execute_reply.started":"2023-10-08T23:12:34.701923Z","shell.execute_reply":"2023-10-08T23:12:34.707832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img","metadata":{"execution":{"iopub.status.busy":"2023-10-08T23:12:38.531412Z","iopub.execute_input":"2023-10-08T23:12:38.531871Z","iopub.status.idle":"2023-10-08T23:12:38.854085Z","shell.execute_reply.started":"2023-10-08T23:12:38.531839Z","shell.execute_reply":"2023-10-08T23:12:38.852209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}