init
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
# Default ignored files
 | 
			
		||||
/shelf/
 | 
			
		||||
/workspace.xml
 | 
			
		||||
# Editor-based HTTP Client requests
 | 
			
		||||
/httpRequests/
 | 
			
		||||
# Datasource local storage ignored files
 | 
			
		||||
/dataSources/
 | 
			
		||||
/dataSources.local.xml
 | 
			
		||||
							
								
								
									
										6
									
								
								.idea/inspectionProfiles/profiles_settings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
<component name="InspectionProjectProfileManager">
 | 
			
		||||
  <settings>
 | 
			
		||||
    <option name="USE_PROJECT_PROFILE" value="false" />
 | 
			
		||||
    <version value="1.0" />
 | 
			
		||||
  </settings>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										17
									
								
								.idea/jupyter-settings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="JupyterPersistentConnectionParameters">
 | 
			
		||||
    <option name="moduleParameters">
 | 
			
		||||
      <map>
 | 
			
		||||
        <entry key="$PROJECT_DIR$/.idea/pythonProject.iml">
 | 
			
		||||
          <value>
 | 
			
		||||
            <JupyterConnectionParameters>
 | 
			
		||||
              <option name="managed" value="true" />
 | 
			
		||||
              <option name="sdkName" value="Python 3.10 (pythonProject)" />
 | 
			
		||||
            </JupyterConnectionParameters>
 | 
			
		||||
          </value>
 | 
			
		||||
        </entry>
 | 
			
		||||
      </map>
 | 
			
		||||
    </option>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										7
									
								
								.idea/misc.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="Black">
 | 
			
		||||
    <option name="sdkName" value="Python 3.10 (pythonProject)" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pythonProject)" project-jdk-type="Python SDK" />
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="ProjectModuleManager">
 | 
			
		||||
    <modules>
 | 
			
		||||
      <module fileurl="file://$PROJECT_DIR$/.idea/pythonProject.iml" filepath="$PROJECT_DIR$/.idea/pythonProject.iml" />
 | 
			
		||||
    </modules>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										6
									
								
								.idea/other.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="PySciProjectComponent">
 | 
			
		||||
    <option name="PY_INTERACTIVE_PLOTS_SUGGESTED" value="true" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										8
									
								
								.idea/pythonProject.iml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<module type="PYTHON_MODULE" version="4">
 | 
			
		||||
  <component name="NewModuleRootManager">
 | 
			
		||||
    <content url="file://$MODULE_DIR$" />
 | 
			
		||||
    <orderEntry type="inheritedJdk" />
 | 
			
		||||
    <orderEntry type="sourceFolder" forTests="false" />
 | 
			
		||||
  </component>
 | 
			
		||||
</module>
 | 
			
		||||
							
								
								
									
										106
									
								
								.ipynb_checkpoints/image_classification_dataset-checkpoint.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,106 @@
 | 
			
		|||
{
 | 
			
		||||
 "cells": [
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "raw",
 | 
			
		||||
   "source": "MNIST数据集 (LeCun et al., 1998) 是图像分类中广泛使用的数据集之一,但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集 (Xiao et al., 2017)。",
 | 
			
		||||
   "id": "58ac648c45d06f50"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {
 | 
			
		||||
    "ExecuteTime": {
 | 
			
		||||
     "end_time": "2024-05-19T04:24:31.687065Z",
 | 
			
		||||
     "start_time": "2024-05-19T04:24:22.281131Z"
 | 
			
		||||
    }
 | 
			
		||||
   },
 | 
			
		||||
   "cell_type": "code",
 | 
			
		||||
   "source": [
 | 
			
		||||
    "import tensorflow as tf\n",
 | 
			
		||||
    "from d2l import tensorflow as d2l\n",
 | 
			
		||||
    "\n",
 | 
			
		||||
    "d2l.use_svg_display()"
 | 
			
		||||
   ],
 | 
			
		||||
   "id": "4f19e5d16d0a7341",
 | 
			
		||||
   "outputs": [
 | 
			
		||||
    {
 | 
			
		||||
     "name": "stderr",
 | 
			
		||||
     "output_type": "stream",
 | 
			
		||||
     "text": [
 | 
			
		||||
      "2024-05-19 12:24:22.318857: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  SSE4.1 SSE4.2 AVX AVX2 FMA\n",
 | 
			
		||||
      "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n"
 | 
			
		||||
     ]
 | 
			
		||||
    }
 | 
			
		||||
   ],
 | 
			
		||||
   "execution_count": 1
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "raw",
 | 
			
		||||
   "source": [
 | 
			
		||||
    "3.5.1. 读取数据集\n",
 | 
			
		||||
    "我们可以通过框架中的内置函数将Fashion-MNIST数据集下载并读取到内存中。"
 | 
			
		||||
   ],
 | 
			
		||||
   "id": "c67a3433075cb8ed"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "code",
 | 
			
		||||
   "outputs": [],
 | 
			
		||||
   "execution_count": null,
 | 
			
		||||
   "source": "mnist_train, mnist_test = tf.keras.datasets.fashion_mnist.load_data()",
 | 
			
		||||
   "id": "e5defd40322a3af2"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "raw",
 | 
			
		||||
   "source": "Fashion-MNIST由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像 和测试数据集(test dataset)中的1000张图像组成。 因此,训练集和测试集分别包含60000和10000张图像。 测试数据集不会用于训练,只用于评估模型性能。",
 | 
			
		||||
   "id": "9f2c0b217b6b5e30"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "code",
 | 
			
		||||
   "outputs": [],
 | 
			
		||||
   "execution_count": null,
 | 
			
		||||
   "source": "len(mnist_train[0]), len(mnist_test[0])",
 | 
			
		||||
   "id": "6129edd7e9c7e9fc"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "markdown",
 | 
			
		||||
   "source": [
 | 
			
		||||
    "每个输入图像的高度和宽度均为28像素。 数据集由灰度图像组成,其通道数为1。 为了简洁起见,本书将高度\n",
 | 
			
		||||
    "h像素、宽度w像素图像的形状记hxw或(h,w)。"
 | 
			
		||||
   ],
 | 
			
		||||
   "id": "719bd9e11b3b06a9"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
   "metadata": {},
 | 
			
		||||
   "cell_type": "code",
 | 
			
		||||
   "outputs": [],
 | 
			
		||||
   "execution_count": null,
 | 
			
		||||
   "source": "mnist_train[0][0].shape",
 | 
			
		||||
   "id": "3ed7450fafac4f36"
 | 
			
		||||
  }
 | 
			
		||||
 ],
 | 
			
		||||
 "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": 5
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								20240507153436.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 133 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240507153436.png.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240507173217.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 414 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240507173217.png.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240517105758.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 55 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105800.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105802.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 57 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105803.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 55 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105805.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105806.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 56 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105808.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 52 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105810.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 55 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105812.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 54 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105813.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 62 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105815.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 54 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105816.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105818.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 43 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105820.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 53 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105821.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 57 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105823.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 57 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105824.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 54 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105826.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 53 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105828.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517105829.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 50 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517115712.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 62 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517115712.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240517135556.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517135556.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240517140142.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517140142.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240517140325.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 60 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517140325.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								20240517140418.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 57 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								20240517140418.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								IMG_3584.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.4 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3585.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.4 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3592.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.1 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3593.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.1 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3594.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.4 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3596.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.4 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3599.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								IMG_3604.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 748 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3606.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 425 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								IMG_3684.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 632 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Sneaker.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 150 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Sneaker.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 56 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Snipaste_2024-05-01_21-10-47.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 943 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Trouser.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								WechatIMG7309.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.8 MiB  | 
							
								
								
									
										64
									
								
								check-1.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
import numpy as np
 | 
			
		||||
from numpy.fft import fft2, ifft2, fftshift, ifftshift
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
from PIL import Image
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def modify_amplitude_only(image_path, u, v, factor):
 | 
			
		||||
    """
 | 
			
		||||
    修改图像B通道在(u, v)位置的频率分量的幅度,并保持相位不变。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    image_path: 输入图像的路径。
 | 
			
		||||
    u, v: 要修改的频率分量的位置。
 | 
			
		||||
    factor: 幅度修改因子。
 | 
			
		||||
 | 
			
		||||
    返回:
 | 
			
		||||
    original_amplitude: 原始幅度。
 | 
			
		||||
    modified_amplitude: 修改后的预期幅度。
 | 
			
		||||
    current_amplitude: 实际当前幅度。
 | 
			
		||||
    """
 | 
			
		||||
    # 读取图像
 | 
			
		||||
    image = np.array(Image.open(image_path))
 | 
			
		||||
    B_channel = image[:, :, 2]  # 提取B通道
 | 
			
		||||
 | 
			
		||||
    N, M = B_channel.shape
 | 
			
		||||
    F = fftshift(fft2(B_channel))
 | 
			
		||||
 | 
			
		||||
    # 获取原始的幅度和相位
 | 
			
		||||
    original_amplitude = np.abs(F[u, v])
 | 
			
		||||
 | 
			
		||||
    # 修改幅度
 | 
			
		||||
    amplitude = np.abs(F)
 | 
			
		||||
    phase = np.angle(F)
 | 
			
		||||
    amplitude[u, v] *= factor
 | 
			
		||||
    amplitude[N - u, M - v] *= factor  # 确保共轭对称
 | 
			
		||||
    modified_amplitude = amplitude[u, v]
 | 
			
		||||
    # 重新构造频域数据
 | 
			
		||||
    F_new = amplitude * np.exp(1j * phase)
 | 
			
		||||
    modified_B_channel = np.real(ifft2(ifftshift(F_new)))  # 执行逆FFT并取实部
 | 
			
		||||
 | 
			
		||||
    # 合并修改后的B通道回原图
 | 
			
		||||
    modified_image = image.copy()
 | 
			
		||||
    modified_image[:, :, 2] = modified_B_channel.astype(np.float64)
 | 
			
		||||
 | 
			
		||||
    # 从修改后的完整图像中提取B通道并进行DFT
 | 
			
		||||
    modified_B_channel_from_image = modified_image[:, :, 2]
 | 
			
		||||
    F_check = fftshift(fft2(modified_B_channel_from_image))
 | 
			
		||||
    current_amplitude = np.abs(F_check[u, v])
 | 
			
		||||
 | 
			
		||||
    return original_amplitude, modified_amplitude, current_amplitude
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 示例使用
 | 
			
		||||
image_path = 'demo_border.png'  # 你的图像路径
 | 
			
		||||
u, v = 128, 128  # 选择要修改的频点位置
 | 
			
		||||
factor = 20  # 幅度增加因子
 | 
			
		||||
 | 
			
		||||
# 修改图像并获取数据
 | 
			
		||||
original_amplitude, modified_amplitude, current_amplitude = modify_amplitude_only(image_path, u, v, factor)
 | 
			
		||||
 | 
			
		||||
# 输出幅度数据对比
 | 
			
		||||
print(f"Original Amplitude at ({u}, {v}): {original_amplitude}")
 | 
			
		||||
print(f"Modified Amplitude (expected) at ({u}, {v}): {modified_amplitude}")
 | 
			
		||||
print(f"Current Amplitude (after modification and IFFT) at ({u}, {v}): {current_amplitude}")
 | 
			
		||||
							
								
								
									
										93
									
								
								check.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
import numpy as np
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
from numpy.fft import fft2, ifft2, fftshift, ifftshift
 | 
			
		||||
from PIL import Image
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
def modify_b_channel_frequency(image, modify_pos, factor):
 | 
			
		||||
    # 提取B通道并进行FFT
 | 
			
		||||
    b_channel = image[:, :, 2]
 | 
			
		||||
    f_b = fftshift(fft2(b_channel))
 | 
			
		||||
    # 图像尺寸
 | 
			
		||||
    N, M = b_channel.shape
 | 
			
		||||
    amplitude = np.abs(f_b)
 | 
			
		||||
    phase = np.angle(f_b)
 | 
			
		||||
    # 获取修改位置的原始幅度
 | 
			
		||||
    x, y = modify_pos
 | 
			
		||||
    original_amplitude = np.abs(f_b[x, y])
 | 
			
		||||
 | 
			
		||||
    # 修改指定位置的频率幅度
 | 
			
		||||
 | 
			
		||||
    amplitude[x,y] = original_amplitude * factor
 | 
			
		||||
    modified_amplitude = amplitude[x, y]
 | 
			
		||||
    amplitude[N-x, M-y] = amplitude[N-x, M-y] * factor
 | 
			
		||||
    # modified_amplitude = original_amplitude
 | 
			
		||||
    f_b = amplitude * np.exp(1j * phase)
 | 
			
		||||
 | 
			
		||||
    # 执行逆FFT转换回空间域
 | 
			
		||||
    modified_b_channel = ifft2(ifftshift(f_b))
 | 
			
		||||
    modified_b_channel = np.real(modified_b_channel)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # 保证修改后的B通道在合法范围内
 | 
			
		||||
    # modified_b_channel = np.clip(modified_b_channel, 0, 255).astype(np.uint8)
 | 
			
		||||
 | 
			
		||||
    # 合并修改后的B通道回原图
 | 
			
		||||
    # image[:, :, 2] = modified_b_channel
 | 
			
		||||
 | 
			
		||||
    # 返回修改前后的幅度信息
 | 
			
		||||
    return image, original_amplitude, modified_amplitude, modified_b_channel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_modification_effect(image, modify_pos):
 | 
			
		||||
    # 再次进行FFT以检查修改效果
 | 
			
		||||
    # b_channel = image[:, :, 2]
 | 
			
		||||
    b_channel = image
 | 
			
		||||
    f_b = fftshift(fft2(b_channel))
 | 
			
		||||
    x, y = modify_pos
 | 
			
		||||
    current_amplitude = np.abs(f_b[x, y])
 | 
			
		||||
    return current_amplitude, f_b
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 加载图像
 | 
			
		||||
img_path = 'demo_border.png'
 | 
			
		||||
image = np.array(Image.open(img_path))
 | 
			
		||||
 | 
			
		||||
# 设置修改位置和放大因子
 | 
			
		||||
modify_pos = (110, 125)  # 修改位置
 | 
			
		||||
factor = 2 # 放大原有的幅度
 | 
			
		||||
 | 
			
		||||
# 修改B通道并检查效果
 | 
			
		||||
modified_image, original_amplitude, modified_amplitude, modified_b_channel = modify_b_channel_frequency(image, modify_pos, factor)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
image[:, :, 2] = modified_b_channel
 | 
			
		||||
filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
 | 
			
		||||
Image.fromarray(image).save(filename)
 | 
			
		||||
 | 
			
		||||
# final_image = Image.fromarray(image)
 | 
			
		||||
# final_image.save(filename)
 | 
			
		||||
#
 | 
			
		||||
img = Image.open(filename)
 | 
			
		||||
img = np.array(img)
 | 
			
		||||
b_channel = img[:, :, 2]
 | 
			
		||||
 | 
			
		||||
current_amplitude, f_b = check_modification_effect(modified_b_channel, modify_pos)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 输出幅度对比
 | 
			
		||||
print(f"Original Amplitude: {original_amplitude}")
 | 
			
		||||
print(f"Modified Amplitude (should be): {modified_amplitude}")
 | 
			
		||||
print(f"Current Amplitude (after modifications and IFFT): {current_amplitude}")
 | 
			
		||||
# 打印出f_b中最大幅度
 | 
			
		||||
# print(f"Maximum Amplitude in f_b: {np.max(np.abs(f_b))}")
 | 
			
		||||
 | 
			
		||||
# 可视化显示
 | 
			
		||||
plt.figure(figsize=(12, 6))
 | 
			
		||||
plt.subplot(121)
 | 
			
		||||
plt.imshow(image)
 | 
			
		||||
plt.title('Original Image')
 | 
			
		||||
plt.subplot(122)
 | 
			
		||||
plt.imshow(modified_image)
 | 
			
		||||
plt.title('Modified Image')
 | 
			
		||||
plt.show()
 | 
			
		||||
							
								
								
									
										55755
									
								
								color_balance_model.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								corrected_image.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 288 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								corrected_image.tiff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										139
									
								
								creare_pdf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,139 @@
 | 
			
		|||
import os
 | 
			
		||||
import tempfile
 | 
			
		||||
 | 
			
		||||
import cv2
 | 
			
		||||
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, DateTime,TIMESTAMP
 | 
			
		||||
from fpdf import FPDF
 | 
			
		||||
import io
 | 
			
		||||
import hashlib
 | 
			
		||||
import requests
 | 
			
		||||
import secrets
 | 
			
		||||
from PIL import Image
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
import matplotlib.image as mpimg
 | 
			
		||||
 | 
			
		||||
import demo
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# from  demo import perspective_transform
 | 
			
		||||
 | 
			
		||||
def init_sqlserver():
 | 
			
		||||
    # 创建连接引擎
 | 
			
		||||
    engine = create_engine('postgresql://postgres:!1q2w3E*@8.134.85.73:5432/postgres')
 | 
			
		||||
    # 连接数据库
 | 
			
		||||
    connection = engine.connect()
 | 
			
		||||
    print("Connection to PostgreSQL DB successful")
 | 
			
		||||
    # 声明表结构
 | 
			
		||||
    metadata = MetaData()
 | 
			
		||||
    qrcode_data = Table('qrcode_data', metadata,
 | 
			
		||||
                        Column('key', String),
 | 
			
		||||
                        Column('circles', String),
 | 
			
		||||
                        # createdate 时间类型
 | 
			
		||||
                        Column('createdate', TIMESTAMP)
 | 
			
		||||
                        )
 | 
			
		||||
    return qrcode_data
 | 
			
		||||
 | 
			
		||||
def get_images(key, secret, api, count=1):
 | 
			
		||||
    images = []
 | 
			
		||||
    urls = []
 | 
			
		||||
    for i in range(count):
 | 
			
		||||
        random_number = ''.join([str(secrets.randbelow(9) + 1) for _ in range(16)])
 | 
			
		||||
        parm = f"api_key={key}&cliD={random_number}&cliT=D1&return_file={secret}"
 | 
			
		||||
        params = {
 | 
			
		||||
            "api_key": key,
 | 
			
		||||
            "cliT": "D2",
 | 
			
		||||
            "cliD": random_number,
 | 
			
		||||
            "return_file": ""
 | 
			
		||||
        }
 | 
			
		||||
        # 排序
 | 
			
		||||
        sorted_params = sorted(params.items())
 | 
			
		||||
        concatenated_params = '&'.join(f"{key}={value}" for key, value in sorted_params)
 | 
			
		||||
        data = concatenated_params + secret
 | 
			
		||||
        hash_object = hashlib.md5(data.encode())
 | 
			
		||||
        md5_hash = hash_object.hexdigest()
 | 
			
		||||
        url = f"{api}?api_key={key}&cliT=D2&cliD={random_number}&sign={md5_hash}&return_file="
 | 
			
		||||
        urls.append(url)
 | 
			
		||||
    for url in urls:
 | 
			
		||||
        response = requests.get(url)
 | 
			
		||||
        images.append(response.content)
 | 
			
		||||
 | 
			
		||||
    return images
 | 
			
		||||
 | 
			
		||||
def ndarray_to_binary(image_array):
 | 
			
		||||
    # 将numpy数组转换为PIL图像对象
 | 
			
		||||
    img = Image.fromarray(image_array)
 | 
			
		||||
    # 创建一个字节流对象
 | 
			
		||||
    byte_arr = io.BytesIO()
 | 
			
		||||
    # 将图像保存到字节流中,格式可以自选,如PNG
 | 
			
		||||
    img.save(byte_arr, format='PNG')
 | 
			
		||||
    # 获取二进制数据
 | 
			
		||||
    binary_data = byte_arr.getvalue()
 | 
			
		||||
    return binary_data
 | 
			
		||||
 | 
			
		||||
def create_pdf(images, fileName):
 | 
			
		||||
    # 创建 PDF 类实例
 | 
			
		||||
    pdf = FPDF('P', 'mm', 'A4')
 | 
			
		||||
    # 添加一页
 | 
			
		||||
    pdf.add_page()
 | 
			
		||||
    # 设置图片的尺寸
 | 
			
		||||
    image_width = 15  # 图片宽度 30 mm
 | 
			
		||||
    image_height = 15  # 图片高度 30 mm
 | 
			
		||||
    margin = 20  # 页边距 10 mm
 | 
			
		||||
    images_per_row = 5
 | 
			
		||||
    # 当前行的开始位置
 | 
			
		||||
    x_offset = margin
 | 
			
		||||
    y_offset = margin
 | 
			
		||||
    # 自定义临时文件路径
 | 
			
		||||
    custom_temp_dir = './temp'
 | 
			
		||||
    os.makedirs(custom_temp_dir, exist_ok=True)
 | 
			
		||||
    # 循环处理图片二进制数据
 | 
			
		||||
    for i, binary_image in enumerate(images):
 | 
			
		||||
        if i % images_per_row == 0 and i != 0:
 | 
			
		||||
            # 开始新的一行
 | 
			
		||||
            x_offset = margin
 | 
			
		||||
            y_offset += image_height + margin
 | 
			
		||||
        # # 将binary_image保存为本地文件
 | 
			
		||||
        # with open(f"{i}.png", "wb") as f:
 | 
			
		||||
        #     f.write(binary_image)
 | 
			
		||||
 | 
			
		||||
        # 创建一个临时文件来保存图像
 | 
			
		||||
        with tempfile.NamedTemporaryFile(delete=False, suffix=".TIFF", dir=custom_temp_dir) as tmpfile:
 | 
			
		||||
            tmpfile.write(binary_image)
 | 
			
		||||
            tmp_filename = tmpfile.name
 | 
			
		||||
            print(tmp_filename)
 | 
			
		||||
            if os.access(tmp_filename, os.R_OK):
 | 
			
		||||
                print("File is readable.")
 | 
			
		||||
            else:
 | 
			
		||||
                print("File is not readable.")
 | 
			
		||||
 | 
			
		||||
        img_path = demo.exec_image_result(tmp_filename)
 | 
			
		||||
        # 将img_path返回来 tiff 格式转换 png 格式
 | 
			
		||||
        img = Image.open(img_path)
 | 
			
		||||
        png_path = img_path.replace('.tiff', '.png')
 | 
			
		||||
        img.save(png_path, format='PNG')
 | 
			
		||||
        # 添加图片
 | 
			
		||||
        pdf.image(png_path, x=x_offset, y=y_offset, w=image_width, h=image_height)
 | 
			
		||||
        # 更新x坐标
 | 
			
		||||
        x_offset += image_width + margin
 | 
			
		||||
        # 删除文件
 | 
			
		||||
        os.remove(tmp_filename)
 | 
			
		||||
    # 输出 PDF
 | 
			
		||||
    pdf.output(fileName)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
key = "CL8ca5c629b676d724"
 | 
			
		||||
secret = "7a92463b491be3d0aa9704a8980e46ad"
 | 
			
		||||
api = "https://open-api.cli.im/cli-open-platform-service/v1/labelStyle/createWithKey"
 | 
			
		||||
 | 
			
		||||
# 初始化数据库
 | 
			
		||||
# qrcode_entity = init_sqlserver()
 | 
			
		||||
images = get_images(key, secret, api, count=1)
 | 
			
		||||
create_pdf(images, "qr_v2.pdf")
 | 
			
		||||
 | 
			
		||||
# for i in range(10):
 | 
			
		||||
#     # 生成16位随机数字
 | 
			
		||||
#     random_number = ''.join([str(secrets.randbelow(10)) for _ in range(16)])
 | 
			
		||||
#     # 将随机数字每两位分为一组
 | 
			
		||||
#     # groups = [random_number[i:i + 2] for i in range(0, len(random_number), 2)]
 | 
			
		||||
#     # print(groups)
 | 
			
		||||
							
								
								
									
										69
									
								
								create_iamge_border.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
from PIL import Image, ImageOps
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
def add_yellow_border(image_path, output_path, border_size=2):
 | 
			
		||||
    """
 | 
			
		||||
    给指定的图像添加黄色外边框并保存。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    image_path (str): 原始图像的路径。
 | 
			
		||||
    output_path (str): 带边框的图像保存路径。
 | 
			
		||||
    border_size (int): 边框的像素宽度,默认为2。
 | 
			
		||||
    """
 | 
			
		||||
    # 打开图像
 | 
			
		||||
    img = Image.open(image_path)
 | 
			
		||||
 | 
			
		||||
    # 计算边框颜色和大小
 | 
			
		||||
    # 灰色
 | 
			
		||||
    # border_color = (192, 192, 192)
 | 
			
		||||
    border_color = (255, 255, 0)
 | 
			
		||||
    border = (border_size, border_size, border_size, border_size)  # (左, 上, 右, 下)
 | 
			
		||||
 | 
			
		||||
    # 添加边框
 | 
			
		||||
    img_with_border = ImageOps.expand(img, border=border, fill=border_color)
 | 
			
		||||
 | 
			
		||||
    # 保存新图像
 | 
			
		||||
    img_with_border.save(output_path)
 | 
			
		||||
    print(f"Image saved with a yellow border to {output_path}")
 | 
			
		||||
 | 
			
		||||
def find_qr_code_border_and_save(image_path):
 | 
			
		||||
    # 读取图像
 | 
			
		||||
    img = cv2.imread(image_path)
 | 
			
		||||
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 | 
			
		||||
 | 
			
		||||
    # 边缘检测
 | 
			
		||||
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
 | 
			
		||||
 | 
			
		||||
    # 霍夫变换检测直线
 | 
			
		||||
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=100, maxLineGap=10)
 | 
			
		||||
    print(lines)
 | 
			
		||||
    # 初始化最小和最大的x和y值
 | 
			
		||||
    min_x, max_x = img.shape[1], 0
 | 
			
		||||
    min_y, max_y = img.shape[0], 0
 | 
			
		||||
 | 
			
		||||
    if lines is not None:
 | 
			
		||||
        # 更新x和y的最小和最大值来找到边界框
 | 
			
		||||
        for line in lines:
 | 
			
		||||
            x1, y1, x2, y2 = line[0]
 | 
			
		||||
            min_x = min(min_x, x1, x2)
 | 
			
		||||
            max_x = max(max_x, x1, x2)
 | 
			
		||||
            min_y = min(min_y, y1, y2)
 | 
			
		||||
            max_y = max(max_y, y1, y2)
 | 
			
		||||
 | 
			
		||||
        # 截取二维码区域
 | 
			
		||||
        qr_code_region = img[min_y:max_y, min_x:max_x]
 | 
			
		||||
 | 
			
		||||
        # 保存截取的图片
 | 
			
		||||
        cv2.imwrite('qr_code_detected.png', qr_code_region)
 | 
			
		||||
        print("二维码区域已保存为 'qr_code_detected.png'")
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        print("未检测到任何直线")
 | 
			
		||||
 | 
			
		||||
# 示例用法
 | 
			
		||||
# image_path = '20240506202950.png'  # 替换为你的图像路径 jkkkkkkkkkk
 | 
			
		||||
# output_path = '20240506202950_border.png'  # 替换为保存新图像的路径
 | 
			
		||||
# add_yellow_border(image_path, output_path,5)
 | 
			
		||||
 | 
			
		||||
find_qr_code_border_and_save('IMG_3565.png')
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								demo-1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.6 KiB  | 
							
								
								
									
										490
									
								
								demo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,490 @@
 | 
			
		|||
import os
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, DateTime,TIMESTAMP
 | 
			
		||||
import psycopg2
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
from numpy.fft import fft2, fftshift, ifft2, ifftshift
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
from PIL import Image, ImageOps
 | 
			
		||||
import random
 | 
			
		||||
from skimage.measure import label, regionprops
 | 
			
		||||
import math
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
# 创建连接引擎
 | 
			
		||||
engine = create_engine('postgresql://postgres:!1q2w3E*@8.134.85.73:5432/postgres')
 | 
			
		||||
# 连接数据库
 | 
			
		||||
connection = engine.connect()
 | 
			
		||||
print("Connection to PostgreSQL DB successful")
 | 
			
		||||
# 声明表结构
 | 
			
		||||
metadata = MetaData()
 | 
			
		||||
qrcode_data = Table('qrcode_data', metadata,
 | 
			
		||||
                  Column('key', String),
 | 
			
		||||
                  Column('circles', String),
 | 
			
		||||
                    # createdate 时间类型
 | 
			
		||||
                    Column('createdate', TIMESTAMP)
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
def create_filter_with_only_circles_and_generate(size, cutoff_radius, num_circles, circle_radius):
 | 
			
		||||
    """
 | 
			
		||||
    创建一个仅包含指定数量圆形的滤波器。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    size: 滤波器的大小(宽度和高度相同)。
 | 
			
		||||
    cutoff_radius: 低频区域的半径,确保所有圆都在此区域内。
 | 
			
		||||
    num_circles: 滤波器中要生成的圆的数量。
 | 
			
		||||
    circle_radius: 圆的半径。
 | 
			
		||||
 | 
			
		||||
    返回值:
 | 
			
		||||
    一个二进制滤波器数组,其中圆的区域值为1,其他区域值为0。
 | 
			
		||||
    """
 | 
			
		||||
    filter = np.zeros((size, size))  # 初始化滤波器数组
 | 
			
		||||
    center_x, center_y = size // 2, size // 2  # 计算滤波器中心点坐标
 | 
			
		||||
    circles = []  # 存储已生成圆的列表
 | 
			
		||||
    max_attempts = 1000  # 设置最大尝试次数,以避免无限循环
 | 
			
		||||
 | 
			
		||||
    while len(circles) < num_circles and max_attempts > 0:  # 循环,直到生成足够数量的不重叠圆
 | 
			
		||||
        # 随机生成圆心位置,确保圆完全位于低频区域内
 | 
			
		||||
        angle = random.uniform(0, 2 * np.pi)
 | 
			
		||||
        r = random.uniform(0, cutoff_radius - circle_radius)
 | 
			
		||||
        x = int(center_x + r * np.cos(angle))
 | 
			
		||||
        y = int(center_y + r * np.sin(angle))
 | 
			
		||||
 | 
			
		||||
        # 检查新生成的圆是否与已存在的圆重叠
 | 
			
		||||
        overlapping = False
 | 
			
		||||
        for cx, cy, cr in circles:
 | 
			
		||||
            if np.sqrt((x - cx) ** 2 + (y - cy) ** 2) < (circle_radius + cr):
 | 
			
		||||
                overlapping = True
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if not overlapping:  # 如果新圆不与任何已存在圆重叠,则添加到列表中
 | 
			
		||||
            circles.append((x, y, circle_radius))
 | 
			
		||||
            max_attempts -= 1
 | 
			
		||||
 | 
			
		||||
    # 为每个生成的圆,在滤波器数组中设置对应区域的值为1
 | 
			
		||||
    for (x, y, radius) in circles:
 | 
			
		||||
        for i in range(-radius, radius + 1):
 | 
			
		||||
            for j in range(-radius, radius + 1):
 | 
			
		||||
                if np.sqrt(i ** 2 + j ** 2) <= radius:
 | 
			
		||||
                    filter[x + i, y + j] = 1  # 设置圆形区域的值为1
 | 
			
		||||
 | 
			
		||||
    return filter
 | 
			
		||||
 | 
			
		||||
def generate_circles_in_frequency_domain(size, cutoff_radius, num_circles, circle_radius):
 | 
			
		||||
    """
 | 
			
		||||
    生成指定数量的圆形,用于频域操作。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    size: 频域的大小(宽度和高度相同)。
 | 
			
		||||
    cutoff_radius: 低频区域的半径,确保所有圆都在此区域内。
 | 
			
		||||
    num_circles: 要生成的圆的数量。
 | 
			
		||||
    circle_radius: 圆的半径。
 | 
			
		||||
 | 
			
		||||
    返回值:
 | 
			
		||||
    一个列表,包含每个圆的 (中心x坐标, 中心y坐标, 半径) 元组。
 | 
			
		||||
    """
 | 
			
		||||
    center_x, center_y = size // 2, size // 2  # 计算频域中心点坐标
 | 
			
		||||
    circles = []  # 存储已生成圆的列表
 | 
			
		||||
    max_attempts = 1000  # 设置最大尝试次数,以避免无限循环
 | 
			
		||||
 | 
			
		||||
    while len(circles) < num_circles and max_attempts > 0:  # 循环,直到生成足够数量的不重叠圆
 | 
			
		||||
        # 随机生成圆心位置,确保圆完全位于低频区域内
 | 
			
		||||
        angle = random.uniform(0, 2 * np.pi)
 | 
			
		||||
        r = random.uniform(0, cutoff_radius - circle_radius)
 | 
			
		||||
        x = int(center_x + r * np.cos(angle))
 | 
			
		||||
        y = int(center_y + r * np.sin(angle))
 | 
			
		||||
 | 
			
		||||
        # 检查新生成的圆是否与已存在的圆重叠
 | 
			
		||||
        overlapping = False
 | 
			
		||||
        for cx, cy, cr in circles:
 | 
			
		||||
            if np.sqrt((x - cx) ** 2 + (y - cy) ** 2) < (circle_radius + cr):
 | 
			
		||||
                overlapping = True
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if not overlapping:  # 如果新圆不与任何已存在圆重叠,则添加到列表中
 | 
			
		||||
            circles.append((x, y, circle_radius))
 | 
			
		||||
            max_attempts -= 1
 | 
			
		||||
 | 
			
		||||
    return circles
 | 
			
		||||
 | 
			
		||||
def draw_circles_on_frequency_domain(size, circles):
 | 
			
		||||
    """
 | 
			
		||||
    在频域图中绘制圆形。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    size: 频域的大小(宽度和高度相同)。
 | 
			
		||||
    circles: 包含每个圆的 (中心x坐标, 中心y坐标, 半径) 元组的列表。
 | 
			
		||||
 | 
			
		||||
    返回值:
 | 
			
		||||
    一个二维数组,表示频域图,其中圆形区域的值为1,其他区域的值为0。
 | 
			
		||||
    """
 | 
			
		||||
    frequency_domain_image = np.zeros((size, size))  # 初始化频域图数组
 | 
			
		||||
 | 
			
		||||
    # 遍历所有圆并在频域图中绘制它们
 | 
			
		||||
    for (x, y, radius) in circles:
 | 
			
		||||
        for i in range(-radius, radius + 1):
 | 
			
		||||
            for j in range(-radius, radius + 1):
 | 
			
		||||
                if i**2 + j**2 <= radius**2:  # 判断点是否在圆内
 | 
			
		||||
                    # 检查绘制点是否在图像范围内
 | 
			
		||||
                    if 0 <= x + i < size and 0 <= y + j < size:
 | 
			
		||||
                        frequency_domain_image[x + i, y + j] = 1
 | 
			
		||||
 | 
			
		||||
    return frequency_domain_image
 | 
			
		||||
 | 
			
		||||
def find_circles_in_filter(filter_array):
 | 
			
		||||
    """
 | 
			
		||||
    从滤波器数组中识别圆形区域,提取每个圆的中心和半径。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    filter_array (ndarray): 一个二维数组,其中圆形区域的值为1,其他为0。
 | 
			
		||||
 | 
			
		||||
    返回:
 | 
			
		||||
    list: 每个圆的 (中心x坐标, 中心y坐标, 半径) 元组列表。
 | 
			
		||||
    """
 | 
			
		||||
    labeled_image = label(filter_array)  # 标记连通区域
 | 
			
		||||
    regions = regionprops(labeled_image)  # 提取区域属性
 | 
			
		||||
    circles = []
 | 
			
		||||
    for region in regions:
 | 
			
		||||
        if region.area >= 5:  # 排除太小的区域,假定它们不是我们要找的圆
 | 
			
		||||
            radius = np.sqrt(region.area / np.pi)  # 计算半径
 | 
			
		||||
            circles.append((region.centroid[1], region.centroid[0], radius))  # x, y顺序要反转,因为centroid给出的是(row, col)
 | 
			
		||||
    return circles
 | 
			
		||||
 | 
			
		||||
def distribute_points_on_circles(f_shifted, circles, num_points=240):
 | 
			
		||||
    """
 | 
			
		||||
    将点均匀分布在每个圆周上。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    f_shifted: 平移处理的函数图像
 | 
			
		||||
    circles (list of tuples): 每个元组包含一个圆的 (中心x坐标, 中心y坐标, 半径)
 | 
			
		||||
    num_points (int): 每个圆上的点数量,默认为240
 | 
			
		||||
 | 
			
		||||
    返回:
 | 
			
		||||
    list: 每个圆的点坐标列表,每个元素为一个包含240个点的列表,每个点是(x, y)坐标的元组
 | 
			
		||||
    """
 | 
			
		||||
    radians_per_step = 2 * np.pi / num_points  # 计算每个步长的弧度值
 | 
			
		||||
    print('弧度:', radians_per_step)
 | 
			
		||||
    all_circle_points = []  # 存储所有圆的点坐标
 | 
			
		||||
 | 
			
		||||
    for center_x, center_y, radius in circles:
 | 
			
		||||
        # print('中心坐标:', center_x, center_y)
 | 
			
		||||
        circle_points = []  # 存储单个圆的点坐标
 | 
			
		||||
        for i in range(num_points):
 | 
			
		||||
            theta = i * radians_per_step  # 计算当前点的角度弧度
 | 
			
		||||
            x = center_x + radius * np.cos(theta)  # 极坐标转笛卡尔坐标(x)
 | 
			
		||||
            y = center_y + radius * np.sin(theta)  # 极坐标转笛卡尔坐标(y)
 | 
			
		||||
            #通过笛卡尔坐标计算回角度
 | 
			
		||||
            angle_radians = math.atan2(y - center_y, x - center_x)
 | 
			
		||||
            angle_degrees = math.degrees(angle_radians)
 | 
			
		||||
            #保留angle_degrees小数点后1位,四舍五入
 | 
			
		||||
            angle_degrees = round(angle_degrees, 1)
 | 
			
		||||
            #计算x,y坐标点的幅度
 | 
			
		||||
            amplitude = np.abs(f_shifted[int(x), int(y)])
 | 
			
		||||
            #计算x,y坐标点的相位
 | 
			
		||||
            phase = np.angle(f_shifted[int(x), int(y)])
 | 
			
		||||
            #将当前点的坐标,幅度以及相位打印出来
 | 
			
		||||
            # print(f"x: {x}, y: {y}, angle: {angle_degrees}, amplitude: {amplitude}, phase: {phase}")
 | 
			
		||||
            # 将当前点的坐标,幅度以及相位添加到列表
 | 
			
		||||
            circle_points.append((int(x), int(y), angle_degrees, amplitude, phase))  # 添加当前点的坐标到列表
 | 
			
		||||
        all_circle_points.append(circle_points)  # 添加该圆的所有点坐标到主列表
 | 
			
		||||
        #打印出circle_points中最大的幅度
 | 
			
		||||
        # print(f"最大幅度:{max(circle_points, key=lambda x: x[3])[3]}")
 | 
			
		||||
 | 
			
		||||
    # 将all_circle_points每个元素的点坐标根据amplitude进行降序排序
 | 
			
		||||
    # for i in range(len(all_circle_points)):
 | 
			
		||||
    #     all_circle_points[i].sort(key=lambda x: x[3], reverse=True)
 | 
			
		||||
 | 
			
		||||
    packed_circle_points = []
 | 
			
		||||
 | 
			
		||||
    for circle_points in all_circle_points:
 | 
			
		||||
        x, y, angles, amplitudes, phase = zip(*circle_points)
 | 
			
		||||
        packed_circle_points.append((x, y, angles, amplitudes, phase))
 | 
			
		||||
 | 
			
		||||
    return packed_circle_points
 | 
			
		||||
 | 
			
		||||
def degrees_to_radians(degrees):
 | 
			
		||||
    """
 | 
			
		||||
    将角度转换为弧度。
 | 
			
		||||
 | 
			
		||||
    参数:
 | 
			
		||||
    degrees (float): 输入的角度值。
 | 
			
		||||
 | 
			
		||||
    返回:
 | 
			
		||||
    float: 转换后的弧度值。
 | 
			
		||||
    """
 | 
			
		||||
    # 将角度乘以π/180,完成角度到弧度的转换
 | 
			
		||||
    radians = degrees * (math.pi / 180)
 | 
			
		||||
    return radians
 | 
			
		||||
 | 
			
		||||
# 将水印序列编码为二进制字符串
 | 
			
		||||
def encode_watermark_to_binary(watermark_sequence):
 | 
			
		||||
    binary_sequence = []
 | 
			
		||||
    for number in watermark_sequence:
 | 
			
		||||
        # 初始化一个100位全为'0'的二进制字符串
 | 
			
		||||
        binary_100_bit = ['0'] * 100
 | 
			
		||||
        # 在数字对应的位置设置'1'
 | 
			
		||||
        if 0 <= number < 100:
 | 
			
		||||
            binary_100_bit[number-1] = '1'
 | 
			
		||||
        # 连接这些位,形成一个100位的二进制字符串
 | 
			
		||||
        binary_sequence.append(''.join(binary_100_bit))
 | 
			
		||||
    return binary_sequence
 | 
			
		||||
 | 
			
		||||
#解析图片水印
 | 
			
		||||
def process_image_b_component(image_path, circles, watermarks):
 | 
			
		||||
    num_points = 240
 | 
			
		||||
    img = Image.open(image_path)
 | 
			
		||||
    img = np.array(img)
 | 
			
		||||
    # 将img缩放到 256*256
 | 
			
		||||
    # img = cv2.resize(img, (339,339))
 | 
			
		||||
    # img = cv2.resize(img, (500, 500))
 | 
			
		||||
    img = cv2.resize(img, (255, 255))
 | 
			
		||||
    b_channel = img[:, :, 2]
 | 
			
		||||
    # 计算二维DFT并移位,使零频率分量在中心
 | 
			
		||||
    f_transform = fft2(b_channel)
 | 
			
		||||
    f_shifted = fftshift(f_transform)
 | 
			
		||||
    radians_per_step = 2 * np.pi / num_points  # 计算每个步长的弧度值
 | 
			
		||||
    all_circle_points = []  # 存储所有圆的点坐标
 | 
			
		||||
 | 
			
		||||
    for center_x, center_y, radius in circles:
 | 
			
		||||
        # print('中心坐标:', center_x, center_y)
 | 
			
		||||
        circle_points = []  # 存储单个圆的点坐标
 | 
			
		||||
        for i in range(num_points):
 | 
			
		||||
            theta = i * radians_per_step  # 计算当前点的角度弧度
 | 
			
		||||
            x = center_x + radius * np.cos(theta)  # 极坐标转笛卡尔坐标(x)
 | 
			
		||||
            y = center_y + radius * np.sin(theta)  # 极坐标转笛卡尔坐标(y)
 | 
			
		||||
            # 通过笛卡尔坐标计算回角度
 | 
			
		||||
            angle_radians = math.atan2(y - center_y, x - center_x)
 | 
			
		||||
            angle_degrees = math.degrees(angle_radians)
 | 
			
		||||
            # 保留angle_degrees小数点后1位,四舍五入
 | 
			
		||||
            angle_degrees = round(angle_degrees, 1)
 | 
			
		||||
            # 计算x,y坐标点的幅度
 | 
			
		||||
            amplitude = np.abs(f_shifted[int(x), int(y)])
 | 
			
		||||
            # 计算x,y坐标点的相位
 | 
			
		||||
            phase = np.angle(f_shifted[int(x), int(y)])
 | 
			
		||||
            # 将当前点的坐标,幅度以及相位打印出来
 | 
			
		||||
            print(f"x: {int(x)}, y: {int(y)}, angle: {angle_degrees}, amplitude: {amplitude}, phase: {phase}")
 | 
			
		||||
            # 将当前点的坐标,幅度以及相位添加到列表
 | 
			
		||||
            circle_points.append((int(x), int(y), angle_degrees, amplitude, phase))  # 添加当前点的坐标到列表
 | 
			
		||||
        all_circle_points.append(circle_points)  # 添加该圆的所有点坐标到主列表
 | 
			
		||||
 | 
			
		||||
    watermark_result = []
 | 
			
		||||
    #遍历all_circle_points
 | 
			
		||||
    for i in range(len(all_circle_points)):
 | 
			
		||||
        print(f"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 第{i + 1}个圆")
 | 
			
		||||
        w = watermarks[i]
 | 
			
		||||
        isOk = False
 | 
			
		||||
        # 将all_circle_points每个元素的点坐标根据amplitude进行降序排序
 | 
			
		||||
        all_circle_points[i].sort(key=lambda x: x[3], reverse=True)
 | 
			
		||||
        # 打印all_circle_points[i]中每个元素
 | 
			
		||||
        for j in range(16):  # 只考虑每个圆的前四个最大幅度
 | 
			
		||||
            point = all_circle_points[i][j]
 | 
			
		||||
            print(f"幅度排名 {j + 1}: x: {point[0]}, y: {point[1]}, 角度: {point[2]}, 幅度: {point[3]}, 相位: {point[4]}")
 | 
			
		||||
            # 处理角度,使其在0到360度范围内
 | 
			
		||||
            adjusted_angle = point[2] if point[2] >= 0 else point[2] + 360
 | 
			
		||||
            # 计算并打印当前角度是圆上的第几份
 | 
			
		||||
            fraction_index = adjusted_angle / 1.5 + 1
 | 
			
		||||
            if w == fraction_index:
 | 
			
		||||
                print(f"水印匹配成功!角度:{adjusted_angle} , 编码:{fraction_index}")
 | 
			
		||||
                # 将当前fraction_index添加到结果列表中,保留整数位
 | 
			
		||||
                watermark_result.append(int(fraction_index))
 | 
			
		||||
                isOk = True
 | 
			
		||||
                break
 | 
			
		||||
        if isOk == False:
 | 
			
		||||
            watermark_result.append(0)
 | 
			
		||||
 | 
			
		||||
    return watermark_result, img
 | 
			
		||||
 | 
			
		||||
def calculate_psnr(image1, image2):
 | 
			
		||||
    mse = np.mean((image1 - image2) ** 2)
 | 
			
		||||
    if mse == 0:
 | 
			
		||||
        return float('inf')
 | 
			
		||||
    max_pixel = 255.0
 | 
			
		||||
    psnr = 20 * np.log10(max_pixel / np.sqrt(mse))
 | 
			
		||||
    return psnr
 | 
			
		||||
 | 
			
		||||
def perspective_transform(img_path):
 | 
			
		||||
    if not os.path.exists(img_path):
 | 
			
		||||
        raise FileNotFoundError(f"Image file '{img_path}' not found.")
 | 
			
		||||
    # 通过cv2加载图片
 | 
			
		||||
    img = cv2.imread(img_path)
 | 
			
		||||
    if img is None:
 | 
			
		||||
        raise FileNotFoundError(f"Image file '{img_path}' not found or could not be read.")
 | 
			
		||||
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 | 
			
		||||
    # 复制图片
 | 
			
		||||
    img_copy = img.copy()
 | 
			
		||||
    # 将图片转灰度图
 | 
			
		||||
    img_copy = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
 | 
			
		||||
    # 黑白颜色反转
 | 
			
		||||
    img_copy = cv2.bitwise_not(img_copy)
 | 
			
		||||
    wechatqr = cv2.wechat_qrcode.WeChatQRCode("wechat_qrcode/detect.prototxt", "wechat_qrcode/detect.caffemodel",
 | 
			
		||||
                                              "wechat_qrcode/sr.prototxt", "wechat_qrcode/sr.caffemodel")
 | 
			
		||||
    res, points = wechatqr.detectAndDecode(img_copy)
 | 
			
		||||
    # 在原图上标记二维码的角点
 | 
			
		||||
    if len(res) > 0:
 | 
			
		||||
        # for point in points[0]:
 | 
			
		||||
        #     cv2.circle(img, tuple(int(i) for i in point), 10, (255, 0, 0), -1)  # 红色圆点,半径为10
 | 
			
		||||
        point = points[0]
 | 
			
		||||
        width = max(np.linalg.norm(point[0] - point[1]), np.linalg.norm(point[2] - point[3]))
 | 
			
		||||
        height = max(np.linalg.norm(point[1] - point[2]), np.linalg.norm(point[3] - point[0]))
 | 
			
		||||
        # 不添加边距
 | 
			
		||||
        points_dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=point.dtype)
 | 
			
		||||
        # 生成变换矩阵
 | 
			
		||||
        matrix = cv2.getPerspectiveTransform(point, points_dst)
 | 
			
		||||
        # 应用透视变换,纠正图像
 | 
			
		||||
        corrected_image = cv2.warpPerspective(img, matrix, (int(width), int(height)))
 | 
			
		||||
 | 
			
		||||
        return corrected_image, img, res[0]  # 返回校正后的图像和标记后的原图
 | 
			
		||||
 | 
			
		||||
    return None, img, None  # 如果没有检测到二维码,仅返回原图
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def exec_image_result(img_path):
 | 
			
		||||
    # 设置图像大小和截止频率半径
 | 
			
		||||
    cutoff_radius = 80
 | 
			
		||||
    # 在低通滤波器中添加8个随机圆形区域
 | 
			
		||||
    circle_radius = 15  # 每个圆的半径
 | 
			
		||||
    num_circles = 8  # 圆形数量
 | 
			
		||||
    alpha = 1.5
 | 
			
		||||
    # 加载图片
 | 
			
		||||
    # img_path = 'qr8_1000.png'
 | 
			
		||||
    # img = Image.open(img_path)
 | 
			
		||||
    # img = np.array(img)
 | 
			
		||||
    corrected_image, img, qr_res = perspective_transform(img_path)
 | 
			
		||||
    # 复制一份原图
 | 
			
		||||
    img_copy = corrected_image.copy()
 | 
			
		||||
    # 获取img_copy的size
 | 
			
		||||
    N, M, _ = img_copy.shape
 | 
			
		||||
    print(f"img_copy size: {json.dumps(img_copy.shape)}")
 | 
			
		||||
    # 提取B通道
 | 
			
		||||
    b_channel = corrected_image[:, :, 2]
 | 
			
		||||
    N, M = b_channel.shape
 | 
			
		||||
    # 计算二维DFT并移位,使零频率分量在中心
 | 
			
		||||
    f_transform = fft2(b_channel)
 | 
			
		||||
    f_shifted = fftshift(f_transform)
 | 
			
		||||
    # watermark_sequence = [77, 23, 51, 48, 44, 55, 22, 66]  # 示例数字
 | 
			
		||||
    watermark_sequence = [int(qr_res[i:i + 2]) for i in range(0, len(qr_res), 2)]
 | 
			
		||||
    encoded_watermark = encode_watermark_to_binary(watermark_sequence)
 | 
			
		||||
    # 展开所有的二进制编码成一个长字符串
 | 
			
		||||
    flattened_encoded_watermark = ''.join(encoded_watermark)
 | 
			
		||||
    print(flattened_encoded_watermark)
 | 
			
		||||
    # 生成了指定数量的位于频域中的圆
 | 
			
		||||
    circles = generate_circles_in_frequency_domain(b_channel.shape[0], cutoff_radius, num_circles, circle_radius)
 | 
			
		||||
    # 绘制圆形
 | 
			
		||||
    frequency_domain_image = draw_circles_on_frequency_domain(b_channel.shape[0], circles)
 | 
			
		||||
    # 将circles转成 json
 | 
			
		||||
    circles_json = json.dumps(circles)
 | 
			
		||||
    print(circles_json)
 | 
			
		||||
    # 获取当前时间
 | 
			
		||||
    print(datetime.now())
 | 
			
		||||
    # 保存数据
 | 
			
		||||
    new_qr_data = qrcode_data.insert().values(key=json.dumps(watermark_sequence), circles=json.dumps(circles),
 | 
			
		||||
                                              createdate=datetime.now())
 | 
			
		||||
    connection.execute(new_qr_data)
 | 
			
		||||
    connection.commit()
 | 
			
		||||
    # connection.close()
 | 
			
		||||
    distributed_points = distribute_points_on_circles(f_shifted, circles, 240)
 | 
			
		||||
    # 总幅度
 | 
			
		||||
    f_amplitudes = np.abs(f_shifted)
 | 
			
		||||
    # 总相位
 | 
			
		||||
    f_phase = np.angle(f_shifted)
 | 
			
		||||
    for circle_index, (x, y, angles, amplitudes, phase) in enumerate(distributed_points):
 | 
			
		||||
        # 根据指定的圆圈索引,从编码后的水印中获取对应的元素
 | 
			
		||||
        cw = encoded_watermark[circle_index]
 | 
			
		||||
        # 获取amplitudes的最大值
 | 
			
		||||
        max_amplitude = max(amplitudes)
 | 
			
		||||
        print(f"圆 {circle_index + 1} 的数据: 编码:{cw} ,最大幅度:{max_amplitude}")
 | 
			
		||||
        # 这里我们可以访问每个圆的所有点的坐标、角度和幅度
 | 
			
		||||
        for i in range(len(x)):  # 假设每个圆有相同数量的点,例如240个
 | 
			
		||||
            # print(f"点 {i + 1}: x = {int(x[i])}, y = {int(y[i])}, 角度 = {angles[i]}, 幅度 = {amplitudes[i]}, 相位 = {phase[i]}")
 | 
			
		||||
            if i < len(cw):  # 确保不会超出水印信息的长度
 | 
			
		||||
                bit = cw[i]  # 根据索引获取水印信息的当前位
 | 
			
		||||
                if bit == '1':
 | 
			
		||||
                    original_amplitude = f_amplitudes[x[i], y[i]]
 | 
			
		||||
                    f_amplitudes[x[i], y[i]] = max_amplitude * alpha
 | 
			
		||||
                    f_amplitudes[N - x[i], M - y[i]] = max_amplitude * alpha
 | 
			
		||||
                    modified_amplitude = f_amplitudes[x[i], y[i]]  # alpha是定义的强度因子
 | 
			
		||||
                    # print(f"点 {i + 1}: x = {int(x[i])}, y = {int(y[i])}, 角度 = {angles[i]}, 幅度 = {amplitudes[i]}, 相位 = {phase[i]}")
 | 
			
		||||
                    # print(f"原始幅度:{original_amplitude}")
 | 
			
		||||
                    # 打印嵌入水印信息后幅度
 | 
			
		||||
                    # print(f"嵌入水印信息后幅度: {modified_amplitude}")
 | 
			
		||||
                else:
 | 
			
		||||
                    modified_amplitude = f_amplitudes[x[i], y[i]]
 | 
			
		||||
                # 重新构造复数值并更新频域数据
 | 
			
		||||
                # f_shifted[x[i], y[i]] = modified_amplitude * np.exp(1j * phase[i])
 | 
			
		||||
    f_shifted = f_amplitudes * np.exp(1j * f_phase)
 | 
			
		||||
    # 频域图像转换回空间域
 | 
			
		||||
    img_lowpass_multi_circular = np.real(ifft2(ifftshift(f_shifted)))
 | 
			
		||||
    b_channel = np.clip(img_lowpass_multi_circular, 0, 255).astype(np.uint16)
 | 
			
		||||
    # 合并修改后的通道回到一个新的图像数组中
 | 
			
		||||
    # merged_img = np.stack((r_channel, g_channel, b_channel), axis=-1)
 | 
			
		||||
    corrected_image[:, :, 2] = b_channel
 | 
			
		||||
    final_image = Image.fromarray(corrected_image)
 | 
			
		||||
    # 添加边框
 | 
			
		||||
    final_image_copy = final_image.copy()
 | 
			
		||||
    border_size = 30
 | 
			
		||||
    # border_color = (73, 116, 165)
 | 
			
		||||
    # 设置border_color 为rgb 白色
 | 
			
		||||
    border_color = (255, 255, 255)
 | 
			
		||||
    border = (border_size, border_size, border_size, border_size)  # (左, 上, 右, 下)
 | 
			
		||||
    img_with_border = ImageOps.expand(final_image_copy, border=border, fill=border_color)
 | 
			
		||||
    # 将merged_img保存到文件,文件是为当前时间的字符串
 | 
			
		||||
    filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}.tiff"
 | 
			
		||||
    # cv2.imwrite(filename, merged_img)
 | 
			
		||||
    img_with_border.save(filename, format='TIFF')
 | 
			
		||||
    # 显示结果
 | 
			
		||||
    plt.figure(figsize=(12, 12))
 | 
			
		||||
    plt.subplot(221)
 | 
			
		||||
    plt.title("Original Image")
 | 
			
		||||
    plt.imshow(img_copy, cmap='gray')
 | 
			
		||||
    plt.subplot(222)
 | 
			
		||||
    plt.title("Frequency Spectrum")
 | 
			
		||||
    plt.imshow(np.log1p(np.abs(f_shifted)), cmap='gray')
 | 
			
		||||
    plt.subplot(223)
 | 
			
		||||
    plt.title("Multi Circular Lowpass Filter (50 Points per Circle)")
 | 
			
		||||
    plt.imshow(frequency_domain_image, cmap='gray')
 | 
			
		||||
    plt.subplot(224)
 | 
			
		||||
    plt.title("Filtered Image (Multi Circular Low Frequencies, 50 Points per Circle)")
 | 
			
		||||
    plt.imshow(final_image)
 | 
			
		||||
    plt.tight_layout()
 | 
			
		||||
    plt.show()
 | 
			
		||||
    return filename
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_qr(filename, watermark_sequence):
 | 
			
		||||
    watermarks = [int(watermark_sequence[i:i + 2]) for i in range(0, len(watermark_sequence), 2)]
 | 
			
		||||
    # 根据 key读取数据库圆形信息
 | 
			
		||||
    key = json.dumps(watermarks)
 | 
			
		||||
    circles = []
 | 
			
		||||
    # 查询第一条数据
 | 
			
		||||
    qr = qrcode_data.select().where(qrcode_data.c.key == key)
 | 
			
		||||
    result = connection.execute(qr).first()
 | 
			
		||||
    if result:
 | 
			
		||||
        # 将json字符串转换为列表
 | 
			
		||||
        circles = json.loads(result[1])
 | 
			
		||||
        print(circles)
 | 
			
		||||
        # 验证水印结果
 | 
			
		||||
        result, img2 = process_image_b_component(filename, circles, watermarks)
 | 
			
		||||
        print(result)
 | 
			
		||||
    else:
 | 
			
		||||
        print("未找到数据")
 | 
			
		||||
    # psnr = calculate_psnr(img_copy, img2)
 | 
			
		||||
    # print(f"PSNR: {psnr}")
 | 
			
		||||
    # # PSNR > 40 dB:通常被认为是高质量图像
 | 
			
		||||
    # # 30 dB < PSNR < 40 dB:图像质量是良好
 | 
			
		||||
    # if psnr > 40:
 | 
			
		||||
    #     print("图像质量是高质量")
 | 
			
		||||
    # elif 35 <= psnr < 40:
 | 
			
		||||
    #     print("图像质量是良好")
 | 
			
		||||
    # else:
 | 
			
		||||
    #     print("图像质量是差")
 | 
			
		||||
 | 
			
		||||
# img_path = './temp/tmpb_1ffsve.png'
 | 
			
		||||
# exec_image_result(img_path)
 | 
			
		||||
 | 
			
		||||
img_path = "corrected_image.png"
 | 
			
		||||
qr = "9918314391322762"
 | 
			
		||||
validate_qr(img_path, qr)
 | 
			
		||||
 | 
			
		||||
# perspective_transform(img_path)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								demo_border.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fashion_mnist_model.h5
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										50
									
								
								fashion_test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
import numpy as np
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
from tensorflow.keras.preprocessing import image
 | 
			
		||||
from tensorflow.keras.models import load_model
 | 
			
		||||
import tensorflow as tf
 | 
			
		||||
 | 
			
		||||
# # 加载Fashion-MNIST数据集
 | 
			
		||||
# fashion_mnist = tf.keras.datasets.fashion_mnist
 | 
			
		||||
# (X_train, y_train), (X_test, y_test) = fashion_mnist.load_data()
 | 
			
		||||
#
 | 
			
		||||
# # 数据预处理
 | 
			
		||||
# X_train = X_train / 255.0  # 将像素值缩放到0-1之间
 | 
			
		||||
# X_test = X_test / 255.0
 | 
			
		||||
#
 | 
			
		||||
# # 加载模型
 | 
			
		||||
# model = load_model('fashion_mnist_model.h5')
 | 
			
		||||
#
 | 
			
		||||
# # 评估模型
 | 
			
		||||
# loss, accuracy = model.evaluate(X_test, y_test)
 | 
			
		||||
# print(f'Test Loss: {loss}')
 | 
			
		||||
# print(f'Test Accuracy: {accuracy}')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 图像文件路径
 | 
			
		||||
img_path = '运动鞋.png'
 | 
			
		||||
 | 
			
		||||
# 加载图像并调整大小
 | 
			
		||||
img = image.load_img(img_path, target_size=(28, 28), color_mode='grayscale')
 | 
			
		||||
 | 
			
		||||
# 将PIL图像转换为NumPy数组
 | 
			
		||||
img_array = image.img_to_array(img) / 255.0
 | 
			
		||||
 | 
			
		||||
# 添加批量维度
 | 
			
		||||
img_array = np.expand_dims(img_array, axis=0)
 | 
			
		||||
 | 
			
		||||
# 显示图像
 | 
			
		||||
plt.imshow(img_array[0, :, :, 0], cmap='gray')
 | 
			
		||||
plt.show()
 | 
			
		||||
 | 
			
		||||
# 打印图像数组形状
 | 
			
		||||
print(f'Image array shape: {img_array.shape}')
 | 
			
		||||
 | 
			
		||||
# 加载训练好的模型
 | 
			
		||||
model = load_model('fashion_mnist_model.h5')
 | 
			
		||||
 | 
			
		||||
# 进行预测
 | 
			
		||||
predictions = model.predict(img_array)
 | 
			
		||||
predicted_class = np.argmax(predictions, axis=1)
 | 
			
		||||
print(f'Predicted class: {predicted_class[0]}')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								fashion_train.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
import tensorflow as tf
 | 
			
		||||
from tensorflow.keras.models import Sequential
 | 
			
		||||
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
 | 
			
		||||
 | 
			
		||||
# 加载Fashion-MNIST数据集
 | 
			
		||||
fashion_mnist = tf.keras.datasets.fashion_mnist
 | 
			
		||||
(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data()
 | 
			
		||||
 | 
			
		||||
# 数据预处理
 | 
			
		||||
X_train = X_train / 255.0  # 将像素值缩放到0-1之间
 | 
			
		||||
X_test = X_test / 255.0
 | 
			
		||||
 | 
			
		||||
# 如果使用卷积神经网络(CNN),需要调整数据形状
 | 
			
		||||
X_train = X_train.reshape((X_train.shape[0], 28, 28, 1))
 | 
			
		||||
X_test = X_test.reshape((X_test.shape[0], 28, 28, 1))
 | 
			
		||||
 | 
			
		||||
# 标签数据保持不变
 | 
			
		||||
print(f'Training data shape: {X_train.shape}, Training labels shape: {y_train.shape}')
 | 
			
		||||
print(f'Test data shape: {X_test.shape}, Test labels shape: {y_test.shape}')
 | 
			
		||||
 | 
			
		||||
# 构建模型
 | 
			
		||||
model = Sequential([
 | 
			
		||||
    Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
 | 
			
		||||
    MaxPooling2D((2, 2)),
 | 
			
		||||
    Conv2D(64, (3, 3), activation='relu'),
 | 
			
		||||
    MaxPooling2D((2, 2)),
 | 
			
		||||
    Flatten(),
 | 
			
		||||
    Dense(128, activation='relu'),
 | 
			
		||||
    Dense(10, activation='softmax')  # 输出层使用softmax进行10分类
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
# # 编译模型
 | 
			
		||||
# model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
 | 
			
		||||
#
 | 
			
		||||
# # 训练模型
 | 
			
		||||
# model.fit(X_train, y_train, epochs=15, batch_size=32, validation_split=0.2)
 | 
			
		||||
 | 
			
		||||
early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=3)
 | 
			
		||||
lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-3 * 10**(epoch / 20))
 | 
			
		||||
 | 
			
		||||
model.compile(optimizer=tf.keras.optimizers.Adam(), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
 | 
			
		||||
history = model.fit(X_train, y_train, epochs=100, batch_size=32, validation_split=0.2, callbacks=[early_stopping, lr_schedule])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 评估模型
 | 
			
		||||
loss, accuracy = model.evaluate(X_test, y_test)
 | 
			
		||||
print(f'Test Loss: {loss}')
 | 
			
		||||
print(f'Test Accuracy: {accuracy}')
 | 
			
		||||
 | 
			
		||||
model.save('fashion_mnist_model.h5')
 | 
			
		||||
							
								
								
									
										111
									
								
								find_dominant_color.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,111 @@
 | 
			
		|||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
from sklearn.cluster import KMeans
 | 
			
		||||
from PIL import Image, ImageOps
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
 | 
			
		||||
# 定义函数,透视变换
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
def perspective_transform(img_path):
 | 
			
		||||
    # 通过cv2加载图片
 | 
			
		||||
    img = cv2.imread(img_path)
 | 
			
		||||
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 | 
			
		||||
    # 复制图片
 | 
			
		||||
    img_copy = img.copy()
 | 
			
		||||
    # 将图片转灰度图
 | 
			
		||||
    img_copy = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
 | 
			
		||||
    # 二值化
 | 
			
		||||
    # 使用OTSU阈值算法将灰度图转换为二值图
 | 
			
		||||
    _, binary_image = cv2.threshold(img_copy, 127, 255,  cv2.THRESH_OTSU)
 | 
			
		||||
    # inverted_binary_image = cv2.bitwise_not(binary_image)
 | 
			
		||||
    # 黑白颜色反转
 | 
			
		||||
    img_copy = cv2.bitwise_not(img_copy)
 | 
			
		||||
 | 
			
		||||
    plt.title("Original Image")
 | 
			
		||||
    plt.imshow(img_copy, cmap='gray')
 | 
			
		||||
    plt.show()
 | 
			
		||||
 | 
			
		||||
    wechatqr = cv2.wechat_qrcode.WeChatQRCode("wechat_qrcode/detect.prototxt", "wechat_qrcode/detect.caffemodel",
 | 
			
		||||
                                              "wechat_qrcode/sr.prototxt", "wechat_qrcode/sr.caffemodel")
 | 
			
		||||
    res, points = wechatqr.detectAndDecode(binary_image)
 | 
			
		||||
    # 在原图上标记二维码的角点
 | 
			
		||||
    if len(res) > 0:
 | 
			
		||||
        print(res)
 | 
			
		||||
        # for point in points[0]:
 | 
			
		||||
        #     cv2.circle(img, tuple(int(i) for i in point), 10, (255, 0, 0), -1)  # 红色圆点,半径为10
 | 
			
		||||
 | 
			
		||||
        point = points[0]
 | 
			
		||||
        width = max(np.linalg.norm(point[0] - point[1]), np.linalg.norm(point[2] - point[3]))
 | 
			
		||||
        height = max(np.linalg.norm(point[1] - point[2]), np.linalg.norm(point[3] - point[0]))
 | 
			
		||||
        # 不添加边距
 | 
			
		||||
        points_dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=point.dtype)
 | 
			
		||||
        # 生成变换矩阵
 | 
			
		||||
        matrix = cv2.getPerspectiveTransform(point, points_dst)
 | 
			
		||||
        # 应用透视变换,纠正图像
 | 
			
		||||
        corrected_image = cv2.warpPerspective(img, matrix, (int(width), int(height)))
 | 
			
		||||
 | 
			
		||||
        return corrected_image, img  # 返回校正后的图像和标记后的原图
 | 
			
		||||
 | 
			
		||||
    return None, img  # 如果没有检测到二维码,仅返回原图
 | 
			
		||||
 | 
			
		||||
def perfect_reflectance_white_balance(img):
 | 
			
		||||
    # 将图像从 BGR 转换到 LAB 色彩空间
 | 
			
		||||
    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
 | 
			
		||||
 | 
			
		||||
    # 分离 L, A, B 通道
 | 
			
		||||
    l, a, b = cv2.split(lab)
 | 
			
		||||
 | 
			
		||||
    # 寻找图像中的最亮区域(假设这些是白色区域)
 | 
			
		||||
    max_lightness = np.max(l)
 | 
			
		||||
    L_white = np.where(l == max_lightness)
 | 
			
		||||
 | 
			
		||||
    # 计算这些区域在 A 和 B 通道上的平均值
 | 
			
		||||
    a_white_avg = np.mean(a[L_white])
 | 
			
		||||
    b_white_avg = np.mean(b[L_white])
 | 
			
		||||
 | 
			
		||||
    # 适当调整 A 和 B 通道的平均值,避免过度调整
 | 
			
		||||
    a_shift = (128 - a_white_avg) * 0.1  # 减少调整幅度
 | 
			
		||||
    b_shift = (128 - b_white_avg) * 0.1  # 减少调整幅度
 | 
			
		||||
    a = a.astype(np.float32) + a_shift
 | 
			
		||||
    b = b.astype(np.float32) + b_shift
 | 
			
		||||
 | 
			
		||||
    # 确保 a, b 范围在 0 到 255 之间,并转换回 uint8 类型
 | 
			
		||||
    a = np.clip(a, 0, 255).astype(np.uint8)
 | 
			
		||||
    b = np.clip(b, 0, 255).astype(np.uint8)
 | 
			
		||||
 | 
			
		||||
    # 重新合成 LAB 图像并转换回 BGR 色彩空间
 | 
			
		||||
    lab = cv2.merge([l, a, b])
 | 
			
		||||
    corrected_image = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
 | 
			
		||||
 | 
			
		||||
    return corrected_image
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
corrected_image, img = perspective_transform("IMG_3606.png")
 | 
			
		||||
 | 
			
		||||
# 判断corrected_image不为空
 | 
			
		||||
if corrected_image is not None:
 | 
			
		||||
    # 保存图片文件
 | 
			
		||||
    corrected_image_bgr = cv2.cvtColor(corrected_image, cv2.COLOR_RGB2BGR)
 | 
			
		||||
    cv2.imwrite("corrected_image.png", corrected_image_bgr)
 | 
			
		||||
    # 通过 PIL 显示图片
 | 
			
		||||
    plt.title("Original Image")
 | 
			
		||||
    plt.imshow(corrected_image, cmap='gray')
 | 
			
		||||
    plt.show()
 | 
			
		||||
else:
 | 
			
		||||
    print("目标无法识别")
 | 
			
		||||
 | 
			
		||||
# # 读取图像
 | 
			
		||||
# image = cv2.imread('corrected_image.png')
 | 
			
		||||
# # 应用完美反射白平衡算法
 | 
			
		||||
# white_balanced_image = perfect_reflectance_white_balance(image)
 | 
			
		||||
#
 | 
			
		||||
# # 显示结果
 | 
			
		||||
# cv2.imshow('Original Image', image)
 | 
			
		||||
# cv2.imshow('White Balanced Image', white_balanced_image)
 | 
			
		||||
# cv2.waitKey(0)
 | 
			
		||||
# cv2.destroyAllWindows()
 | 
			
		||||
							
								
								
									
										972
									
								
								image_classification_dataset.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										90
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
# This is a sample Python script.
 | 
			
		||||
 | 
			
		||||
# Press ⌃R to execute it or replace it with your code.
 | 
			
		||||
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
 | 
			
		||||
import numpy as np
 | 
			
		||||
from scipy.fft import fft2, fftshift
 | 
			
		||||
import cv2
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
 | 
			
		||||
def print_hi(name):
 | 
			
		||||
    # Use a breakpoint in the code line below to debug your script.
 | 
			
		||||
    print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def encode_watermark_to_binary(watermark_sequence):
 | 
			
		||||
    binary_sequence = []
 | 
			
		||||
    for number in watermark_sequence:
 | 
			
		||||
        # 初始化一个100位全为'0'的二进制字符串
 | 
			
		||||
        binary_100_bit = ['0'] * 100
 | 
			
		||||
        # 在数字对应的位置设置'1'
 | 
			
		||||
        if 0 <= number < 100:
 | 
			
		||||
            binary_100_bit[number-1] = '1'
 | 
			
		||||
        # 连接这些位,形成一个100位的二进制字符串
 | 
			
		||||
        binary_sequence.append(''.join(binary_100_bit))
 | 
			
		||||
    return binary_sequence
 | 
			
		||||
 | 
			
		||||
def process_image_b_component(image_path):
 | 
			
		||||
    """
 | 
			
		||||
    处理图像的B通道,执行DFT并移动频谱。
 | 
			
		||||
 | 
			
		||||
    :param image_path: 输入图像的路径。
 | 
			
		||||
    :return: 移位后DFT的幅度矩阵。
 | 
			
		||||
    """
 | 
			
		||||
    # 使用合适的库加载图像(例如,PIL, OpenCV)
 | 
			
		||||
    # 这里我们会加载图像并提取B通道
 | 
			
		||||
    # 作为演示,我们将创建一个假的256x256 B通道矩阵
 | 
			
		||||
 | 
			
		||||
    #根据image_path加载图像
 | 
			
		||||
    image = cv2.imread(image_path)
 | 
			
		||||
    # 检查图像是否成功加载
 | 
			
		||||
    if image is None:
 | 
			
		||||
        raise ValueError("无法加载图像,请检查路径是否正确。")
 | 
			
		||||
 | 
			
		||||
    # 确保图像的大小是256x256
 | 
			
		||||
    image_resized = cv2.resize(image, (256, 256))
 | 
			
		||||
 | 
			
		||||
    # 提取B通道
 | 
			
		||||
    b_channel = image_resized[:, :, 0]
 | 
			
		||||
 | 
			
		||||
    # 对B通道矩阵执行DFT
 | 
			
		||||
    dft_result = fft2(b_channel)
 | 
			
		||||
 | 
			
		||||
    # 将零频率分量移动到频谱的中心
 | 
			
		||||
    dft_shifted = fftshift(dft_result)
 | 
			
		||||
 | 
			
		||||
    # 获取移位后DFT的幅度
 | 
			
		||||
    magnitude = np.abs(dft_shifted)
 | 
			
		||||
 | 
			
		||||
    return magnitude
 | 
			
		||||
 | 
			
		||||
def decode_binary_to_watermark(binary_sequence):
 | 
			
		||||
    """
 | 
			
		||||
    Decode the binary sequence back into the original array of numbers.
 | 
			
		||||
 | 
			
		||||
    :param binary_sequence: A list of 100-bit strings representing the binary codes.
 | 
			
		||||
    :return: The original array of numbers.
 | 
			
		||||
    """
 | 
			
		||||
    original_numbers = []
 | 
			
		||||
    for binary_code in binary_sequence:
 | 
			
		||||
        if '1' in binary_code:
 | 
			
		||||
            # Find the index of '1' and convert it back to the original number
 | 
			
		||||
            position = binary_code.index('1') + 1  # Add 1 because the index starts at 0
 | 
			
		||||
            original_number = position
 | 
			
		||||
            original_numbers.append(original_number)
 | 
			
		||||
    return original_numbers
 | 
			
		||||
 | 
			
		||||
# Press the green button in the gutter to run the script.
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    # print_hi('PyCharm')
 | 
			
		||||
    watermark_sequence = [12, 34, 56, 44, 90, 55, 34, 56]
 | 
			
		||||
    result = encode_watermark_to_binary(watermark_sequence)
 | 
			
		||||
    print(result)
 | 
			
		||||
    # # 打印编码后的二进制序列
 | 
			
		||||
    # for binary in result:
 | 
			
		||||
    #     print(binary)
 | 
			
		||||
 | 
			
		||||
    watermark_sequence = decode_binary_to_watermark(result)
 | 
			
		||||
    print(watermark_sequence)
 | 
			
		||||
 | 
			
		||||
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								my_images.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								qr5_border.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 44 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								qr6_border.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								qr8_1000.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 163 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								qr_code_detected.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 950 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/20240510144434.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 90 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/20240510144436.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 90 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/20240510144438.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/20240510144439.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 90 KiB  |