From 9e1dad8637bf921317c202d7cf9f31a086bce3b8 Mon Sep 17 00:00:00 2001
From: karllzy
Date: Thu, 23 Jun 2022 12:33:27 +0800
Subject: [PATCH] add dual_main.py and dual_main_test.py
---
07_pixelwised_detection.ipynb | 370 ++++++++++++++++++++++++++++++++++
dual_main.py | 110 ++++++++++
main.py | 33 ++-
models.py | 83 ++++++--
test_files/dual_main_test.py | 61 ++++++
utils.py | 59 ++++--
6 files changed, 677 insertions(+), 39 deletions(-)
create mode 100644 07_pixelwised_detection.ipynb
create mode 100755 dual_main.py
create mode 100755 test_files/dual_main_test.py
diff --git a/07_pixelwised_detection.ipynb b/07_pixelwised_detection.ipynb
new file mode 100644
index 0000000..42e3fd0
--- /dev/null
+++ b/07_pixelwised_detection.ipynb
@@ -0,0 +1,370 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": true,
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ },
+ "source": [
+ "# 基于像素的识别"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "outputs": [],
+ "source": [
+ "import pickle\n",
+ "import cv2\n",
+ "import numpy as np\n",
+ "from utils import split_xy"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "outputs": [],
+ "source": [
+ "# 一些参数\n",
+ "blk_sz = 1\n",
+ "sensitivity = 1\n",
+ "selected_bands = [127, 201, 202, 294]\n",
+ "tree_num = 1\n",
+ "train_size = 140000\n",
+ "file_name, labeled_image_file = r\"/Volumes/zc/zhouchao/616/calibrated1.raw\", \\\n",
+ "r\"/Volumes/zc/zhouchao/616/label1.bmp\"\n",
+ "\n",
+ "test_dir = \"/Volumes/zc/zhouchao/618(2)/kazhi/\"\n",
+ "\n",
+ "dataset_file = f'./dataset/data_{blk_sz}x{blk_sz}_c{len(selected_bands)}_sen{sensitivity}_1.p'\n",
+ "model_file = f'./models/rf_{blk_sz}x{blk_sz}_c{len(selected_bands)}_{tree_num}_sen{sensitivity}_4.model'"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## 数据集的构建"
+ ],
+ "metadata": {
+ "collapsed": false
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "outputs": [],
+ "source": [
+ "with open(file_name, \"rb\") as f:\n",
+ " data = np.frombuffer(f.read(), dtype=np.float32).reshape((600, 448, 1024)).transpose(0, 2, 1)\n",
+ "data = data[..., selected_bands]\n",
+ "label = cv2.imread(labeled_image_file)\n",
+ "color_dict = {(0, 0, 255): 1, (255, 255, 255): 0, (0, 255, 0): 2, (255, 0, 0): 1, (0, 255, 255): 4,\n",
+ " (255, 255, 0): 5, (255, 0, 255): 6}\n",
+ "x, y = split_xy(data, label, blk_sz, sensitivity=sensitivity, color_dict=color_dict)\n",
+ "with open(dataset_file, 'wb') as f:\n",
+ " pickle.dump((x, y), f)"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## 数据平衡化"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "数据量: 614400\n",
+ "x train (430080, 1, 1, 4), y train (430080,)\n",
+ "x test (184320, 1, 1, 4), y test (184320,)\n",
+ "train (array([589552., 17534., 1208., 0., 1362., 3112., 1632.]), array([0, 1, 2, 3, 4, 5, 6, 7]), ) \n",
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": "",
+ "image/png": "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\n"
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "train (array([412687., 412687., 412687., 0., 412687., 412687., 412687.]), array([0, 1, 2, 3, 4, 5, 6, 7]), ) \n",
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": "",
+ "image/png": "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\n"
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "train (array([23333., 23333., 23334., 0., 23333., 23333., 23334.]), array([0, 1, 2, 3, 4, 5, 6, 7]), ) \n",
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": "",
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmMAAAFlCAYAAACnee/9AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAASnUlEQVR4nO3df6zldZ3f8dd7GWtZd3FVRkJmSIetZFMkKa4TSkOysaVdsbtZ2ESTIelKGpLZGLbRtEkD+4/tHyT6R9fGpJJQsQ7WFSmukbS6XYK7sZtYcLC0CEidKiuzUGa2WsUmuoF994/7ne5l5s694/zgfWZ8PJKT872f8/2e+znfkMtzvt/vOae6OwAAzPip6QkAAPwkE2MAAIPEGADAIDEGADBIjAEADBJjAACDtk1P4GRdeOGFvWvXrulpAABs6ZFHHvmz7t6+0WNnbYzt2rUr+/fvn54GAMCWqupPjveY05QAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIO2TU9gle269T9OTwHOeU9/4Femp7DS/B2CM2/675AjYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAM2jLGquqSqvrDqnqyqh6vqvcu46+vqgeq6hvL/evWbXNbVR2oqqeq6u3rxt9aVY8tj324qmoZf3VVfXoZf6iqdp2B1woAsHJO5MjYi0n+aXf/jSRXJ7mlqi5PcmuSB7v7siQPLj9neWxPkjcnuS7JR6rqvOW57kiyN8lly+26ZfzmJN/t7jcl+VCSD56G1wYAsPK2jLHufq67v7osv5DkySQ7klyfZN+y2r4kNyzL1ye5p7t/1N3fSnIgyVVVdXGSC7r7y93dSe4+apsjz3VfkmuPHDUDADiX/VjXjC2nD9+S5KEkF3X3c8lasCV547LajiTPrNvs4DK2Y1k+evxl23T3i0m+l+QNP87cAADORiccY1X1M0k+k+R93f39zVbdYKw3Gd9sm6PnsLeq9lfV/sOHD281ZQCAlXdCMVZVr8paiH2yu39vGX5+OfWY5f7QMn4wySXrNt+Z5NllfOcG4y/bpqq2JXltku8cPY/uvrO7d3f37u3bt5/I1AEAVtqJvJuyktyV5Mnu/p11D92f5KZl+aYkn1s3vmd5h+SlWbtQ/+HlVOYLVXX18pzvPmqbI8/1ziRfXK4rAwA4p207gXWuSfIbSR6rqkeXsd9O8oEk91bVzUm+neRdSdLdj1fVvUmeyNo7MW/p7peW7d6T5ONJzk/yheWWrMXeJ6rqQNaOiO05tZcFAHB22DLGuvuPs/E1XUly7XG2uT3J7RuM709yxQbjP8wScwAAP0l8Aj8AwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBoyxirqo9V1aGq+tq6sX9eVX9aVY8ut3+w7rHbqupAVT1VVW9fN/7WqnpseezDVVXL+Kur6tPL+ENVtes0v0YAgJV1IkfGPp7kug3GP9TdVy63zydJVV2eZE+SNy/bfKSqzlvWvyPJ3iSXLbcjz3lzku9295uSfCjJB0/ytQAAnHW2jLHu/lKS75zg812f5J7u/lF3fyvJgSRXVdXFSS7o7i93dye5O8kN67bZtyzfl+TaI0fNAADOdadyzdhvVdV/X05jvm4Z25HkmXXrHFzGdizLR4+/bJvufjHJ95K8YaNfWFV7q2p/Ve0/fPjwKUwdAGA1nGyM3ZHkrye5MslzSf7lMr7REa3eZHyzbY4d7L6zu3d39+7t27f/WBMGAFhFJxVj3f18d7/U3X+R5N8kuWp56GCSS9atujPJs8v4zg3GX7ZNVW1L8tqc+GlRAICz2knF2HIN2BG/nuTIOy3vT7JneYfkpVm7UP/h7n4uyQtVdfVyPdi7k3xu3TY3LcvvTPLF5boyAIBz3ratVqiqTyV5W5ILq+pgkvcneVtVXZm104lPJ/nNJOnux6vq3iRPJHkxyS3d/dLyVO/J2jszz0/yheWWJHcl+URVHcjaEbE9p+F1AQCcFbaMse6+cYPhuzZZ//Ykt28wvj/JFRuM/zDJu7aaBwDAucgn8AMADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAM2jLGqupjVXWoqr62buz1VfVAVX1juX/dusduq6oDVfVUVb193fhbq+qx5bEPV1Ut46+uqk8v4w9V1a7T/BoBAFbWiRwZ+3iS644auzXJg919WZIHl59TVZcn2ZPkzcs2H6mq85Zt7kiyN8lly+3Ic96c5Lvd/aYkH0rywZN9MQAAZ5stY6y7v5TkO0cNX59k37K8L8kN68bv6e4fdfe3khxIclVVXZzkgu7+cnd3kruP2ubIc92X5NojR80AAM51J3vN2EXd/VySLPdvXMZ3JHlm3XoHl7Edy/LR4y/bprtfTPK9JG84yXkBAJxVTvcF/Bsd0epNxjfb5tgnr9pbVfurav/hw4dPcooAAKvjZGPs+eXUY5b7Q8v4wSSXrFtvZ5Jnl/GdG4y/bJuq2pbktTn2tGiSpLvv7O7d3b17+/btJzl1AIDVcbIxdn+Sm5blm5J8bt34nuUdkpdm7UL9h5dTmS9U1dXL9WDvPmqbI8/1ziRfXK4rAwA4523baoWq+lSStyW5sKoOJnl/kg8kubeqbk7y7STvSpLufryq7k3yRJIXk9zS3S8tT/WerL0z8/wkX1huSXJXkk9U1YGsHRHbc1peGQDAWWDLGOvuG4/z0LXHWf/2JLdvML4/yRUbjP8wS8wBAPyk8Qn8AACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAoFOKsap6uqoeq6pHq2r/Mvb6qnqgqr6x3L9u3fq3VdWBqnqqqt6+bvyty/McqKoPV1WdyrwAAM4Wp+PI2N/p7iu7e/fy861JHuzuy5I8uPycqro8yZ4kb05yXZKPVNV5yzZ3JNmb5LLldt1pmBcAwMo7E6cpr0+yb1nel+SGdeP3dPePuvtbSQ4kuaqqLk5yQXd/ubs7yd3rtgEAOKedaox1kj+oqkeqau8ydlF3P5cky/0bl/EdSZ5Zt+3BZWzHsnz0+DGqam9V7a+q/YcPHz7FqQMAzNt2ittf093PVtUbkzxQVV/fZN2NrgPrTcaPHey+M8mdSbJ79+4N1wEAOJuc0pGx7n52uT+U5LNJrkry/HLqMcv9oWX1g0kuWbf5ziTPLuM7NxgHADjnnXSMVdVrqupnjywn+eUkX0tyf5KbltVuSvK5Zfn+JHuq6tVVdWnWLtR/eDmV+UJVXb28i/Ld67YBADinncppyouSfHb5FIptSX63u3+/qr6S5N6qujnJt5O8K0m6+/GqujfJE0leTHJLd7+0PNd7knw8yflJvrDcAADOeScdY939zSR/c4Px/53k2uNsc3uS2zcY35/kipOdCwDA2con8AMADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMEmMAAIPEGADAIDEGADBIjAEADBJjAACDxBgAwCAxBgAwSIwBAAwSYwAAg8QYAMAgMQYAMEiMAQAMWpkYq6rrquqpqjpQVbdOzwcA4JWwEjFWVecl+ddJ3pHk8iQ3VtXls7MCADjzViLGklyV5EB3f7O7/zzJPUmuH54TAMAZtyoxtiPJM+t+PriMAQCc07ZNT2BRG4z1MStV7U2yd/nxB1X11BmdVXJhkj87w7/jbGcfbc7+2UJ90D7agv2zNftoc/bPFl6hv0N/7XgPrEqMHUxyybqfdyZ59uiVuvvOJHe+UpOqqv3dvfuV+n1nI/toc/bP1uyjzdk/W7OPNmf/bG16H63KacqvJLmsqi6tqr+SZE+S+4fnBABwxq3EkbHufrGqfivJf0pyXpKPdffjw9MCADjjViLGkqS7P5/k89PzOMordkr0LGYfbc7+2Zp9tDn7Z2v20ebsn62N7qPqPuY6eQAAXiGrcs0YAMBPJDF2HL6eaXNV9bGqOlRVX5ueyyqqqkuq6g+r6smqeryq3js9p1VSVX+1qh6uqv+27J9/MT2nVVVV51XVf62q/zA9l1VTVU9X1WNV9WhV7Z+ezyqqqp+rqvuq6uvL36O/PT2nVVFVv7D8t3Pk9v2qet/IXJymPNby9Uz/I8nfz9rHbnwlyY3d/cToxFZIVf1Skh8kubu7r5iez6qpqouTXNzdX62qn03ySJIb/De0pqoqyWu6+wdV9aokf5zkvd39X4antnKq6p8k2Z3kgu7+1en5rJKqejrJ7u72GVrHUVX7kvzn7v7o8mkFP93d/2d4Witn+f/+nyb5W939J6/073dkbGO+nmkL3f2lJN+Znseq6u7nuvury/ILSZ6Mb5X4/3rND5YfX7Xc/MvwKFW1M8mvJPno9Fw4+1TVBUl+KcldSdLdfy7EjuvaJP9zIsQSMXY8vp6J06aqdiV5S5KHhqeyUpbTb48mOZTkge62f471r5L8syR/MTyPVdVJ/qCqHlm+oYWX+/kkh5P82+VU90er6jXTk1pRe5J8auqXi7GNndDXM8FWqupnknwmyfu6+/vT81kl3f1Sd1+ZtW/cuKqqnO5ep6p+Ncmh7n5kei4r7Jru/sUk70hyy3L5BH9pW5JfTHJHd78lyf9N4hrooyynb38tyb+fmoMY29gJfT0TbGa5FuozST7Z3b83PZ9VtZw2+aMk183OZOVck+TXluui7knyd6vq381OabV097PL/aEkn83aJSb8pYNJDq476nxf1uKMl3tHkq929/NTExBjG/P1TJyS5QL1u5I82d2/Mz2fVVNV26vq55bl85P8vSRfH53Uiunu27p7Z3fvytrfoC929z8cntbKqKrXLG+OyXLq7ZeTeHf3Ot39v5I8U1W/sAxdm8SbiI51YwZPUSYr9An8q8TXM22tqj6V5G1JLqyqg0ne3913zc5qpVyT5DeSPLZcF5Ukv7180wTJxUn2Le9g+qkk93a3j27gx3FRks+u/bsn25L8bnf//uyUVtI/TvLJ5cDCN5P8o+H5rJSq+umsfXLCb47Ow0dbAADMcZoSAGCQGAMAGCTGAAAGiTEAgEFiDABgkBgDABgkxgAABokxAIBB/w8Klw/0gTGlTgAAAABJRU5ErkJggg==\n"
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "140000\n"
+ ]
+ }
+ ],
+ "source": [
+ "from matplotlib import pyplot as plt\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from models import train_rf_and_report\n",
+ "from imblearn.over_sampling import RandomOverSampler\n",
+ "\n",
+ "# 读取数据\n",
+ "with open(dataset_file, 'rb') as f:\n",
+ " x_list, y_list = pickle.load(f)\n",
+ "# 确保数据当中x和y数量对得上\n",
+ "assert len(x_list) == len(y_list)\n",
+ "print(\"数据量: \", len(x_list))\n",
+ "x, y = np.asarray(x_list), np.asarray(y_list, dtype=int)\n",
+ "x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=5,\n",
+ " shuffle=True, stratify=y)\n",
+ "print(f\"x train {x_train.shape}, y train {y_train.shape}\\n\"\n",
+ " f\"x test {x_test.shape}, y test {y_test.shape}\")\n",
+ "fig, axs = plt.subplots(figsize=(10, 6))\n",
+ "hist_res_train = axs.hist(y, [0, 1, 2, 3, 4, 5, 6, 7], align='mid')\n",
+ "print(f'train {hist_res_train} \\n')\n",
+ "plt.show()\n",
+ "\n",
+ "ros = RandomOverSampler(random_state=0)\n",
+ "x_train_shape = x_train.shape\n",
+ "x_train = x_train.reshape((x_train.shape[0], -1))\n",
+ "x_resampled, y_resampled = ros.fit_resample(x_train, y_train)\n",
+ "# 画图\n",
+ "fig, axs = plt.subplots(figsize=(10, 6))\n",
+ "hist_res_train = axs.hist(y_resampled, [0, 1, 2, 3, 4, 5, 6, 7], align='mid')\n",
+ "print(f'train {hist_res_train} \\n')\n",
+ "plt.show()\n",
+ "# 抽样\n",
+ "x_train, _, y_train, _ = train_test_split(x_resampled, y_resampled, train_size=train_size, random_state=0, shuffle=True, stratify=y_resampled)\n",
+ "# 画图\n",
+ "fig, axs = plt.subplots(figsize=(10, 6))\n",
+ "hist_res_train = axs.hist(y_train, [0, 1, 2, 3, 4, 5, 6, 7], align='mid')\n",
+ "print(f'train {hist_res_train} \\n')\n",
+ "plt.show()\n",
+ "x_train = x_train.reshape(x_train.shape[0], x_train_shape[1], x_train_shape[2], x_train_shape[3])\n",
+ "print(len(x_train))"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## 模型训练"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "预测时间: 0.032733917236328125\n",
+ "训练集acc:1.0\n",
+ "测试集acc:0.9790999348958334\n",
+ "--------------------------------------------------\n",
+ "测试集报告\n",
+ " precision recall f1-score support\n",
+ "\n",
+ " 0 1.00 0.98 0.99 589552\n",
+ " 1 0.72 0.96 0.82 17534\n",
+ " 2 0.66 0.89 0.76 1208\n",
+ " 4 0.71 0.86 0.77 1362\n",
+ " 5 0.48 0.87 0.62 3112\n",
+ " 6 0.43 0.90 0.58 1632\n",
+ "\n",
+ " accuracy 0.98 614400\n",
+ " macro avg 0.66 0.91 0.76 614400\n",
+ "weighted avg 0.99 0.98 0.98 614400\n",
+ "\n",
+ "混淆矩阵:\n",
+ "[[578285 6281 383 204 2593 1806]\n",
+ " [ 166 16849 69 187 233 30]\n",
+ " [ 8 36 1075 47 37 5]\n",
+ " [ 4 104 52 1166 34 2]\n",
+ " [ 56 147 48 43 2716 102]\n",
+ " [ 31 21 8 1 103 1468]]\n",
+ "二分类报告:\n",
+ " precision recall f1-score support\n",
+ "\n",
+ " 0 1.00 0.99 1.00 607086\n",
+ " 2 0.56 0.94 0.70 7314\n",
+ "\n",
+ " accuracy 0.99 614400\n",
+ " macro avg 0.78 0.97 0.85 614400\n",
+ "weighted avg 0.99 0.99 0.99 614400\n",
+ "\n",
+ "二混淆矩阵:\n",
+ "[[601581 5505]\n",
+ " [ 407 6907]]\n"
+ ]
+ }
+ ],
+ "source": [
+ "from models import feature\n",
+ "from models import train_t_and_report\n",
+ "\n",
+ "features_train = feature(x_train)\n",
+ "features_test = feature(x_test)\n",
+ "feature_x = feature(x)\n",
+ "clf = train_t_and_report(features_train, y_train, feature_x, y, save_path=model_file)"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## 模型评估"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "outputs": [
+ {
+ "data": {
+ "text/plain": "",
+ "image/png": "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\n"
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from models import PixelWisedDetector\n",
+ "from utils import visualization_evaluation\n",
+ "\n",
+ "clf = PixelWisedDetector(model_path=model_file, channel_num=len(selected_bands))\n",
+ "visualization_evaluation(detector=clf, data_path=test_dir, selected_bands=selected_bands)"
+ ],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "outputs": [],
+ "source": [],
+ "metadata": {
+ "collapsed": false,
+ "pycharm": {
+ "name": "#%%\n"
+ }
+ }
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
\ No newline at end of file
diff --git a/dual_main.py b/dual_main.py
new file mode 100755
index 0000000..abef7cc
--- /dev/null
+++ b/dual_main.py
@@ -0,0 +1,110 @@
+import os
+import numpy as np
+from models import SpecDetector, PixelWisedDetector
+from root_dir import ROOT_DIR
+from multiprocessing import Process, Queue
+
+nrows, ncols, nbands = 256, 1024, 4
+img_fifo_path = "/tmp/dkimg.fifo"
+mask_fifo_path = "/tmp/dkmask.fifo"
+cmd_fifo_path = '/tmp/tobacco_cmd.fifo'
+
+pxl_model_path = "rf_1x1_c4_1_sen1_4.model"
+blk_model_path = "rf_8x8_c4_185_sen32_4.model"
+
+
+def main(pxl_model_path=pxl_model_path, blk_model_path=blk_model_path):
+ # 启动两个模型线程
+ blk_cmd_queue, pxl_cmd_queue = Queue(maxsize=100), Queue(maxsize=100)
+ blk_img_queue, pxl_img_queue = Queue(maxsize=100), Queue(maxsize=100)
+ blk_msk_queue, pxl_msk_queue = Queue(maxsize=100), Queue(maxsize=100)
+ blk_process = Process(target=block_model, args=(blk_cmd_queue, blk_img_queue, blk_msk_queue, blk_model_path, ))
+ pxl_process = Process(target=pixel_model, args=(pxl_cmd_queue, pxl_img_queue, pxl_msk_queue, pxl_model_path, ))
+ blk_process.start()
+ pxl_process.start()
+ total_len = nrows * ncols * nbands * 4
+ if not os.access(img_fifo_path, os.F_OK):
+ os.mkfifo(img_fifo_path, 0o777)
+ if not os.access(mask_fifo_path, os.F_OK):
+ os.mkfifo(mask_fifo_path, 0o777)
+ data = b''
+ while True:
+ fd_img = os.open(img_fifo_path, os.O_RDONLY)
+ while len(data) < total_len:
+ data += os.read(fd_img, total_len)
+ if len(data) > total_len:
+ data_total = data[:total_len]
+ data = data[total_len:]
+ else:
+ data_total = data
+ data = b''
+ os.close(fd_img)
+
+ img = np.frombuffer(data_total, dtype=np.float32).reshape((nrows, nbands, -1)).transpose(0, 2, 1)
+ print(f"get img shape {img.shape}")
+ pxl_img_queue.put(img)
+ blk_img_queue.put(img)
+ pxl_msk = pxl_msk_queue.get()
+ blk_msk = blk_msk_queue.get()
+ mask = pxl_msk & blk_msk
+ print(f"predict success get mask shape: {mask.shape}")
+ # 写出
+ fd_mask = os.open(mask_fifo_path, os.O_WRONLY)
+ os.write(fd_mask, mask.tobytes())
+ os.close(fd_mask)
+
+
+def block_model(cmd_queue: Queue, img_queue: Queue, mask_queue: Queue, blk_model_path=blk_model_path):
+ blk_model = SpecDetector(os.path.join(ROOT_DIR, "models", blk_model_path), blk_sz=8, channel_num=4)
+ _ = blk_model.predict(np.ones((nrows, ncols, nbands)))
+ rigor_rate = 70
+ while True:
+ # deal with the cmd if cmd_queue is not empty
+ if not cmd_queue.empty():
+ cmd = cmd_queue.get()
+ if isinstance(cmd, int):
+ rigor_rate = cmd
+ elif isinstance(cmd, str):
+ if cmd == 'stop':
+ break
+ else:
+ try:
+ blk_model_path = SpecDetector(os.path.join(ROOT_DIR, "models", blk_model_path),
+ blk_sz=8, channel_num=4)
+ except Exception as e:
+ print(f"Load Model Failed! {e}")
+ # deal with the img if img_queue is not empty
+ if not img_queue.empty():
+ img = img_queue.get()
+ mask = blk_model.predict(img, rigor_rate)
+ mask_queue.put(mask)
+
+
+def pixel_model(cmd_queue: Queue, img_queue: Queue, mask_queue: Queue, pixel_model_path=pxl_model_path):
+ pixel_model = PixelWisedDetector(os.path.join(ROOT_DIR, "models", pixel_model_path), blk_sz=1, channel_num=4)
+ _ = pixel_model.predict(np.ones((nrows, ncols, nbands)))
+ rigor_rate = 70
+ while True:
+ # deal with the cmd if cmd_queue is not empty
+ if not cmd_queue.empty():
+ cmd = cmd_queue.get()
+ if isinstance(cmd, int):
+ rigor_rate = cmd
+ elif isinstance(cmd, str):
+ if cmd == 'stop':
+ break
+ else:
+ try:
+ pixel_model = PixelWisedDetector(os.path.join(ROOT_DIR, "models", pixel_model_path),
+ blk_sz=1, channel_num=4)
+ except Exception as e:
+ print(f"Load Model Failed! {e}")
+ # deal with the img if img_queue is not empty
+ if not img_queue.empty():
+ img = img_queue.get()
+ mask = pixel_model.predict(img, rigor_rate)
+ mask_queue.put(mask)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/main.py b/main.py
index 15bfc52..5015319 100755
--- a/main.py
+++ b/main.py
@@ -1,31 +1,44 @@
import os
+
+import cv2
import numpy as np
from models import SpecDetector
from root_dir import ROOT_DIR
-nrows, ncols, nbands = 600, 1024, 4
+nrows, ncols, nbands = 256, 1024, 4
img_fifo_path = "/tmp/dkimg.fifo"
mask_fifo_path = "/tmp/dkmask.fifo"
-selected_model = "rf_8x8_c4_400_13.model"
+selected_model = "rf_8x8_c4_185_sen32_4.model"
+
def main():
model_path = os.path.join(ROOT_DIR, "models", selected_model)
detector = SpecDetector(model_path, blk_sz=8, channel_num=4)
- _ = detector.predict(np.ones((600, 1024, 4)))
+ _ = detector.predict(np.ones((256, 1024, 4)))
total_len = nrows * ncols * nbands * 4
+
if not os.access(img_fifo_path, os.F_OK):
os.mkfifo(img_fifo_path, 0o777)
if not os.access(mask_fifo_path, os.F_OK):
os.mkfifo(mask_fifo_path, 0o777)
-
- fd_img = os.open(img_fifo_path, os.O_RDONLY)
- print("connect to fifo")
-
+ data = b''
while True:
- data = os.read(fd_img, total_len)
- print("get img")
- img = np.frombuffer(data, dtype=np.float32).reshape((nrows, nbands, -1)).transpose(0, 2, 1)
+ # 读取
+ fd_img = os.open(img_fifo_path, os.O_RDONLY)
+ while len(data) < total_len:
+ data += os.read(fd_img, total_len)
+ if len(data) > total_len:
+ data_total = data[:total_len]
+ data = data[total_len:]
+ else:
+ data_total = data
+ data = b''
+
+ os.close(fd_img)
+ # 识别
+ img = np.frombuffer(data_total, dtype=np.float32).reshape((nrows, nbands, -1)).transpose(0, 2, 1)
mask = detector.predict(img)
+ # 写出
fd_mask = os.open(mask_fifo_path, os.O_WRONLY)
os.write(fd_mask, mask.tobytes())
os.close(fd_mask)
diff --git a/models.py b/models.py
index ff425f5..3ef77cd 100755
--- a/models.py
+++ b/models.py
@@ -2,13 +2,15 @@ import os
import pickle
import time
-import cv2
import numpy as np
from sklearn.ensemble import RandomForestClassifier
+from sklearn.tree import DecisionTreeClassifier
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
+nrows, ncols, nbands = 256, 1024, 4
+
def feature(x):
x = x.reshape((x.shape[0], -1))
@@ -42,6 +44,31 @@ def train_rf_and_report(train_x, train_y, test_x, test_y,
return rfc
+def train_t_and_report(train_x, train_y, test_x, test_y, save_path=None):
+ rfc = DecisionTreeClassifier(random_state=42, class_weight={0: 10, 1: 10})
+ rfc = rfc.fit(train_x, train_y)
+ t1 = time.time()
+ y_pred = rfc.predict(test_x)
+ y_pred_binary = np.ones_like(y_pred)
+ y_pred_binary[(y_pred == 0) | (y_pred == 1)] = 0
+ y_pred_binary[(y_pred > 1)] = 2
+ test_y_binary = np.ones_like(test_y)
+ test_y_binary[(test_y == 0) | (test_y == 1)] = 0
+ test_y_binary[(test_y > 1)] = 2
+ print("预测时间:", time.time() - t1)
+ print("训练集acc:" + str(accuracy_score(train_y, rfc.predict(train_x))))
+ print("测试集acc:" + str(accuracy_score(test_y, rfc.predict(test_x))))
+ print('-'*50)
+ print('测试集报告\n' + str(classification_report(test_y, y_pred))) # 生成一个小报告呀
+ print('混淆矩阵:\n' + str(confusion_matrix(test_y, y_pred))) # 这个也是,生成的矩阵的意思是有多少
+ print('二分类报告:\n' + str(classification_report(test_y_binary, y_pred_binary))) # 生成一个小报告呀
+ print('二混淆矩阵:\n' + str(confusion_matrix(test_y_binary, y_pred_binary))) # 这个也是,生成的矩阵的意思是有多少
+ if save_path is not None:
+ with open(save_path, 'wb') as f:
+ pickle.dump(rfc, f)
+ return rfc
+
+
def evaluation_and_report(model, test_x, test_y):
t1 = time.time()
y_pred = model.predict(test_x)
@@ -96,21 +123,21 @@ def split_x(data: np.ndarray, blk_sz: int) -> list:
"""
Split the data into slices for classification.将数据划分为多个像素块,便于后续识别.
- ;param data: image data, shape (num_rows x 1024 x num_channels)
+ ;param data: image data, shape (num_rows x ncols x num_channels)
;param blk_sz: block size
;param sensitivity: 最少有多少个杂物点能够被认为是杂物
;return data_x, data_y: sliced data x (block_num x num_charnnels x blk_sz x blk_sz)
"""
x_list = []
- for i in range(0, 600 // blk_sz):
- for j in range(0, 1024 // blk_sz):
+ for i in range(0, nrows // blk_sz):
+ for j in range(0, ncols // blk_sz):
block_data = data[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...]
x_list.append(block_data)
return x_list
class SpecDetector(object):
- def __init__(self, model_path, blk_sz=8, channel_num=4):
+ def __init__(self, model_path, blk_sz=8, channel_num=nbands):
self.blk_sz, self.channel_num = blk_sz, channel_num
if os.path.exists(model_path):
with open(model_path, "rb") as model_file:
@@ -118,20 +145,22 @@ class SpecDetector(object):
else:
raise FileNotFoundError("Model File not found")
- def predict(self, data):
+ def predict(self, data, rigor_rate=70):
blocks = split_x(data, blk_sz=self.blk_sz)
blocks = np.array(blocks)
features = feature(np.array(blocks))
- y_pred = self.clf.predict(features)
- y_pred_binary = np.ones_like(y_pred)
+ print("Spec Detector", rigor_rate)
+ y_pred = self.clf.predict_proba(features)
+ y_pred, y_prob = np.argmax(y_pred, axis=1), np.max(y_pred, axis=1)
+ y_pred_binary = np.zeros_like(y_pred)
# classes merge
- y_pred_binary[(y_pred == 0) | (y_pred == 1) | (y_pred == 3)] = 0
+ y_pred_binary[((y_pred == 2) | (y_pred > 3)) & (y_prob > (100 - rigor_rate) / 100.0)] = 1
# transform to mask
- mask = self.mask_transform(y_pred_binary, (1024, 600))
+ mask = self.mask_transform(y_pred_binary, (ncols, nrows))
return mask
def mask_transform(self, result, dst_size):
- mask_size = 600 // self.blk_sz, 1024 // self.blk_sz
+ mask_size = nrows // self.blk_sz, ncols // self.blk_sz
mask = np.zeros(mask_size, dtype=np.uint8)
for idx, r in enumerate(result):
row, col = idx // mask_size[1], idx % mask_size[1]
@@ -140,8 +169,34 @@ class SpecDetector(object):
return mask
+class PixelWisedDetector(object):
+ def __init__(self, model_path, blk_sz=1, channel_num=nbands):
+ self.blk_sz, self.channel_num = blk_sz, channel_num
+ if os.path.exists(model_path):
+ with open(model_path, "rb") as model_file:
+ self.clf = pickle.load(model_file)
+ else:
+ raise FileNotFoundError("Model File not found")
+
+ def predict(self, data, rigor_rate=70):
+ features = data.reshape((-1, self.channel_num))
+ y_pred = self.clf.predict(features, rigor_rate)
+ y_pred_binary = np.ones_like(y_pred, dtype=np.uint8)
+ print("pixel detector", rigor_rate)
+ # classes merge
+ y_pred_binary[(y_pred == 0) | (y_pred == 1) | (y_pred == 3)] = 0
+ # transform to mask
+ mask = self.mask_transform(y_pred_binary)
+ return mask
+
+ def mask_transform(self, result):
+ mask_size = (nrows, ncols)
+ mask = result.reshape(mask_size)
+ return mask
+
+
class PcaSpecDetector(object):
- def __init__(self, model_path, pca_path, blk_sz=8, channel_num=4):
+ def __init__(self, model_path, pca_path, blk_sz=8, channel_num=nbands):
self.blk_sz, self.channel_num = blk_sz, channel_num
if os.path.exists(model_path):
with open(model_path, "rb") as model_file:
@@ -163,11 +218,11 @@ class PcaSpecDetector(object):
# classes merge
y_pred_binary[(y_pred == 0) | (y_pred == 1) | (y_pred == 3)] = 0
# transform to mask
- mask = self.mask_transform(y_pred_binary, (1024, 600))
+ mask = self.mask_transform(y_pred_binary, (ncols, nrows))
return mask
def mask_transform(self, result, dst_size):
- mask_size = 600 // self.blk_sz, 1024 // self.blk_sz
+ mask_size = nrows // self.blk_sz, ncols // self.blk_sz
mask = np.zeros(mask_size, dtype=np.uint8)
for idx, r in enumerate(result):
row, col = idx // mask_size[1], idx % mask_size[1]
diff --git a/test_files/dual_main_test.py b/test_files/dual_main_test.py
new file mode 100755
index 0000000..b9622a3
--- /dev/null
+++ b/test_files/dual_main_test.py
@@ -0,0 +1,61 @@
+import glob
+import os
+import unittest
+
+import cv2
+import numpy as np
+
+from utils import read_raw_file
+
+nrows, ncols = 256, 1024
+
+
+class DualMainTestCase(unittest.TestCase):
+ def test_dual_main(self):
+ test_img_dirs = '/Volumes/LENOVO_USB_HDD/zhouchao/616_cut/*.raw'
+ selected_bands = None
+ img_fifo_path = "/tmp/dkimg.fifo"
+ mask_fifo_path = "/tmp/dkmask.fifo"
+
+ total_len = nrows * ncols
+ spectral_files = glob.glob(test_img_dirs)
+ print("reading raw files ...")
+ raw_files = [read_raw_file(file, selected_bands=selected_bands) for file in spectral_files]
+ print("reading file success!")
+ if not os.access(img_fifo_path, os.F_OK):
+ os.mkfifo(img_fifo_path, 0o777)
+ if not os.access(mask_fifo_path, os.F_OK):
+ os.mkfifo(mask_fifo_path, 0o777)
+ data = b''
+ for raw_file in raw_files:
+ if raw_file.shape[0] > nrows:
+ raw_file = raw_file[:nrows, ...]
+ # 写出
+ print(f"send {raw_file.shape}")
+ fd_img = os.open(img_fifo_path, os.O_WRONLY)
+ os.write(fd_img, raw_file.tobytes())
+ os.close(fd_img)
+ # 等待
+ fd_mask = os.open(mask_fifo_path, os.O_RDONLY)
+ while len(data) < total_len:
+ data += os.read(fd_mask, total_len)
+ if len(data) > total_len:
+ data_total = data[:total_len]
+ data = data[total_len:]
+ else:
+ data_total = data
+ data = b''
+ os.close(fd_mask)
+ mask = np.frombuffer(data_total, dtype=np.uint8).reshape((-1, ncols))
+
+ # 显示
+ rgb_img = np.asarray(raw_file[..., [0, 2, 3]] * 255, dtype=np.uint8)
+ mask_color = np.zeros_like(rgb_img)
+ mask_color[mask > 0] = (0, 0, 255)
+ combine = cv2.addWeighted(rgb_img, 1, mask_color, 0.5, 0)
+ cv2.imshow("img", combine)
+ cv2.waitKey(0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/utils.py b/utils.py
index 182d2b0..b52cbb6 100755
--- a/utils.py
+++ b/utils.py
@@ -6,9 +6,12 @@ import os
import time
import matplotlib.pyplot as plt
+import tqdm
from models import SpecDetector
+nrows, ncols = 256, 1024
+
def trans_color(pixel: np.ndarray, color_dict: dict = None) -> int:
"""
@@ -35,6 +38,8 @@ def determine_class(pixel_blk: np.ndarray, sensitivity=8) -> int:
:param sensitivity: 敏感度
:return:
"""
+ if (pixel_blk.shape[0] ==1) and (pixel_blk.shape[1] == 1):
+ return pixel_blk[0][0]
defect_dict = {0: 0, 1: 0, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1}
color_numbers = {cls: pixel_blk.shape[0] ** 2 - np.count_nonzero(pixel_blk - cls)
for cls in defect_dict.keys()}
@@ -55,7 +60,7 @@ def split_xy(data: np.ndarray, labeled_img: np.ndarray, blk_sz: int, sensitivity
"""
Split the data into slices for classification.将数据划分为多个像素块,便于后续识别.
- ;param data: image data, shape (num_rows x 1024 x num_channels)
+ ;param data: image data, shape (num_rows x ncols x num_channels)
;param labeled_img: RGB labeled img with respect to the image!
make sure that the defect is (255, 0, 0) and background is (255, 255, 255)
;param blk_sz: block size
@@ -71,8 +76,8 @@ def split_xy(data: np.ndarray, labeled_img: np.ndarray, blk_sz: int, sensitivity
truth_map = np.all(labeled_img == color, axis=2)
class_img[truth_map] = class_idx
x_list, y_list = [], []
- for i in range(0, 600 // blk_sz):
- for j in range(0, 1024 // blk_sz):
+ for i in range(0, nrows // blk_sz):
+ for j in range(0, ncols // blk_sz):
block_data = data[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...]
block_label = class_img[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...]
block_label = determine_class(block_label, sensitivity=sensitivity)
@@ -90,14 +95,14 @@ def split_x(data: np.ndarray, blk_sz: int) -> list:
"""
Split the data into slices for classification.将数据划分为多个像素块,便于后续识别.
- ;param data: image data, shape (num_rows x 1024 x num_channels)
+ ;param data: image data, shape (num_rows x ncols x num_channels)
;param blk_sz: block size
;param sensitivity: 最少有多少个杂物点能够被认为是杂物
;return data_x, data_y: sliced data x (block_num x num_charnnels x blk_sz x blk_sz)
"""
x_list = []
- for i in range(0, 600 // blk_sz):
- for j in range(0, 1024 // blk_sz):
+ for i in range(0, nrows // blk_sz):
+ for j in range(0, ncols // blk_sz):
block_data = data[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...]
x_list.append(block_data)
return x_list
@@ -105,7 +110,6 @@ def split_x(data: np.ndarray, blk_sz: int) -> list:
def visualization_evaluation(detector, data_path, selected_bands=None):
selected_bands = [76, 146, 216, 367, 383, 406] if selected_bands is None else selected_bands
- nrows, ncols = 600, 1024
image_paths = glob.glob(os.path.join(data_path, "calibrated*.raw"))
for idx, image_path in enumerate(image_paths):
with open(image_path, 'rb') as f:
@@ -132,9 +136,9 @@ def visualization_evaluation(detector, data_path, selected_bands=None):
def visualization_y(y_list, k_size):
- mask = np.zeros((600 // k_size, 1024 // k_size), dtype=np.uint8)
+ mask = np.zeros((nrows // k_size, ncols // k_size), dtype=np.uint8)
for idx, r in enumerate(y_list):
- row, col = idx // (1024 // k_size), idx % (1024 // k_size)
+ row, col = idx // (ncols // k_size), idx % (ncols // k_size)
mask[row, col] = r
fig, axs = plt.subplots()
axs.imshow(mask)
@@ -142,16 +146,23 @@ def visualization_y(y_list, k_size):
def read_raw_file(file_name, selected_bands=None):
+ print(f"reading file {file_name}")
with open(file_name, "rb") as f:
- data = np.frombuffer(f.read(), dtype=np.float32).reshape((600, -1, 1024)).transpose(0, 2, 1)
+ data = np.frombuffer(f.read(), dtype=np.float32).reshape((600, -1, ncols)).transpose(0, 2, 1)
if selected_bands is not None:
data = data[..., selected_bands]
return data
+def write_raw_file(file_name, data: np.ndarray):
+ data = data.transpose(0, 2, 1).reshape((nrows, -1, ncols))
+ with open(file_name, 'wb') as f:
+ f.write(data.tobytes())
+
+
def read_black_and_white_file(file_name):
with open(file_name, "rb") as f:
- data = np.frombuffer(f.read(), dtype=np.float32).reshape((1, 448, 1024)).transpose(0, 2, 1)
+ data = np.frombuffer(f.read(), dtype=np.float32).reshape((1, 448, ncols)).transpose(0, 2, 1)
return data
@@ -166,8 +177,8 @@ def generate_tobacco_label(data, model_file, blk_sz, selected_bands):
model = SpecDetector(model_path=model_file, blk_sz=blk_sz, channel_num=len(selected_bands))
y_label = model.predict(data)
x_list, y_list = [], []
- for i in range(0, 600 // blk_sz):
- for j in range(0, 1024 // blk_sz):
+ for i in range(0, nrows // blk_sz):
+ for j in range(0, ncols // blk_sz):
if np.sum(np.sum(y_label[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...])) \
> 0:
block_data = data[i * blk_sz: (i + 1) * blk_sz, j * blk_sz: (j + 1) * blk_sz, ...]
@@ -179,8 +190,8 @@ def generate_tobacco_label(data, model_file, blk_sz, selected_bands):
def generate_impurity_label(data, light_threshold, color_dict, split_line=0, target_class_right=None,
target_class_left=None, ):
y_label = np.zeros((data.shape[0], data.shape[1]))
- for i in range(0, 600):
- for j in range(0, 1024):
+ for i in range(0, nrows):
+ for j in range(0, ncols):
if np.sum(np.sum(data[i, j])) >= light_threshold:
if j > split_line:
y_label[i, j] = target_class_right
@@ -192,3 +203,21 @@ def generate_impurity_label(data, light_threshold, color_dict, split_line=0, tar
axs[1].matshow(data[..., 0])
plt.show()
return pic
+
+
+def file_transform(input_dir, output_dir, selected_bands=None):
+ files = os.listdir(input_dir)
+ filtered_files = [file for file in files if file.endswith('.raw')]
+ os.makedirs(output_dir, mode=0o777, exist_ok=True)
+ for file_path in filtered_files:
+ input_path = os.path.join(input_dir, file_path)
+ output_path = os.path.join(output_dir, file_path)
+ data = read_raw_file(input_path, selected_bands=selected_bands)
+ write_raw_file(output_path, data)
+
+
+if __name__ == '__main__':
+ selected_bands = [127, 201, 202, 294]
+ input_dir, output_dir = r"/Volumes/LENOVO_USB_HDD/zhouchao/616/",\
+ r"/Volumes/LENOVO_USB_HDD/zhouchao/616_cut/"
+ file_transform(input_dir=input_dir, output_dir=output_dir, selected_bands=selected_bands)
\ No newline at end of file