Project files

This commit is contained in:
elena committed 2023-11-09 18:47:11 +01:00
1 parent 695abe054b
commit c415135aae
8554 files changed
+858111

No files matched your search

+430
View File
@@ -0,0 +1,430 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 371,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import argparse\n",
"import imutils\n",
"import cv2\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"import doxapy\n",
"import sys\n",
"from scipy import ndimage\n",
"\n",
"inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/receipe-upload-_oqp9us3.jpg'\n",
"#inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/testbild.png'\n",
"img = cv2.imread(inputfile, cv2.IMREAD_GRAYSCALE)\n",
"start = 200\n",
"stop = start + 700\n",
"\n",
"img_snippet = img[start:stop,:]\n",
"img_copy = cv2.cvtColor(img_snippet,cv2.COLOR_GRAY2RGB)\n",
"\n",
"binary_image = np.empty(img_snippet.shape, img_snippet.dtype)\n",
"sauvola = doxapy.Binarization(doxapy.Binarization.Algorithms.ISAUVOLA)\n",
"sauvola.initialize(img_snippet)\n",
"sauvola.to_binary(binary_image, {\"window\": 45, \"k\": 0.009})\n",
"\n",
"#Plot the snippet\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(binary_image, cmap='gray')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 372,
"metadata": {},
"outputs": [],
"source": [
"#Invert the binary image\n",
"binary_image = cv2.bitwise_not(binary_image)\n",
"# Calc connected components\n",
"num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)\n",
"\n",
"# Calculate the mean vector and the covariance matrix of the pixels in each connected component\n",
"means = np.empty((num_labels,2))\n",
"covs = np.empty((num_labels,2,2))\n",
"eigenvalues = np.empty((num_labels,2))\n",
"eigenvectors = np.empty((num_labels,2,2))\n",
"\n",
"labelsForDelete = []\n",
"\n",
"for i in range(1,num_labels):\n",
" mask = np.zeros(binary_image.shape, np.uint8)\n",
" mask[labels == i] = 255\n",
" \n",
" xy_coords = np.flip(np.column_stack(np.where(mask == 255)), axis=1)\n",
" #means[i] = np.mean(xy_coords, axis=0) # Is equal to the centroid\n",
" covs[i] = np.cov(xy_coords, rowvar=False)\n",
"\n",
" # Calculate the eienvalues and eigenvectors of the covariance matrix\n",
" eigenvalues[i], eigenvectors[i] = np.linalg.eig(covs[i])\n",
"\n",
" #Sort the eigenvalues and eigenvectors\n",
" idx = eigenvalues[i].argsort()[::-1]\n",
" eigenvalues[i] = eigenvalues[i][idx]\n",
" eigenvectors[i] = eigenvectors[i][:,idx]\n",
"\n",
" #If eigenvalue1 / eigenvalue2 > 15, remove the corresponding connected component\n",
" if eigenvalues[i,0] / eigenvalues[i,1] > 15**2:\n",
" labelsForDelete.append(i)\n",
"\n",
"\n",
"#Delete the connected components in list\n",
"labels = np.delete(labels, labelsForDelete, axis=0)\n",
"num_labels = num_labels - len(labelsForDelete)\n",
"stats = np.delete(stats, labelsForDelete, axis=0)\n",
"centroids = np.delete(centroids, labelsForDelete, axis=0)\n",
"eigenvalues = np.delete(eigenvalues, labelsForDelete, axis=0)\n",
"eigenvectors = np.delete(eigenvectors, labelsForDelete, axis=0)\n",
"\n",
"# Create a new image with only the ellipses\n",
"ellipseMask = np.zeros(binary_image.shape, np.uint8)\n",
"for i in range(1,num_labels):\n",
" # Plot eigenvalues as ellipses in black and white image\n",
" cv2.ellipse(ellipseMask,(int(centroids[i,0]),int(centroids[i,1])),(int(np.sqrt(eigenvalues[i,0])),int(np.sqrt(eigenvalues[i,1]))),np.rad2deg(np.arctan2(eigenvectors[i,0,1],eigenvectors[i,0,0])),0,360,(255,255,255),-1)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 373,
"metadata": {},
"outputs": [],
"source": [
"def changes_in_bitoperation(sequence: np.ndarray) -> int:\n",
" '''\n",
" Count the number of bit flips in a binary sequence (2x faster than itertools solution), adopten from: \n",
" https://stackoverflow.com/questions/70300297/is-there-a-built-in-python-function-to-count-bit-flip-in-a-binary-string#:~:text=There%20is%20a%20very%20fast%20way%20to%20do,string%20to%20count%20the%20number%20of%20bit%20flips.\n",
" :param sequence: A binary sequence as a numpy array\n",
" :return: The number of bit flips\n",
" '''\n",
" # Convert the sequence to an integer: [0,1,1,0,1] -> 0b01101\n",
" s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
" n = int(s[1:-1], 2)\n",
"\n",
" # Build a binary mask to skip the most significant bit of n: 0b01101 -> 0b01111\n",
" mask = (1 << (len(s)-1)) - 1\n",
"\n",
" # Check if the ith bit of n is different from the (i+1)th bit of n using a bit-wise XOR:\n",
" # 0b01101 & 0b01111 -> 0b1101 (discard the first bit)\n",
" # 0b01101 >> 1 -> 0b0110\n",
" # 0b1101 ^ 0b0110 -> 0b1011\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" # Convert the integer back to a string and count the bit flips: 0b1011 -> \"0b1011\" -> 3\n",
" flipCount = bin(bitFlips).count('1')\n",
" return flipCount"
]
},
{
"cell_type": "code",
"execution_count": 374,
"metadata": {},
"outputs": [],
"source": [
"def changes_in_bitoperation_v2(sequence: np.ndarray) -> int:\n",
" '''\n",
" Count the number of bit flips in a binary sequence (2x faster than itertools solution), adopten from: \n",
" https://stackoverflow.com/questions/70300297/is-there-a-built-in-python-function-to-count-bit-flip-in-a-binary-string#:~:text=There%20is%20a%20very%20fast%20way%20to%20do,string%20to%20count%20the%20number%20of%20bit%20flips.\n",
" :param sequence: A binary sequence as a numpy array\n",
" :return: The number of bit flips\n",
" '''\n",
" # Convert the sequence to an integer: [0,1,1,0,1] -> 0b01101\n",
" #s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
" # = int(s[1:-1], 2)\n",
" s = sequence.tobytes()\n",
" n = int.from_bytes(s, byteorder='big', signed=False)\n",
"\n",
" # Build a binary mask to skip the most significant bit of n: 0b01101 -> 0b01111\n",
" mask = (1 << (len(s)*8-1)) - 1\n",
"\n",
" # Check if the ith bit of n is different from the (i+1)th bit of n using a bit-wise XOR:\n",
" # 0b01101 & 0b01111 -> 0b1101 (discard the first bit)\n",
" # 0b01101 >> 1 -> 0b0110\n",
" # 0b1101 ^ 0b0110 -> 0b1011\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" # Convert the integer back to a string and count the bit flips: 0b1011 -> \"0b1011\" -> 3\n",
" flipCount = bin(bitFlips).count('1')\n",
" if sequence[0] == 255:\n",
" flipCount += 1\n",
" \n",
" return flipCount"
]
},
{
"cell_type": "code",
"execution_count": 375,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"\\n#np.random.seed(14)\\nimport time\\nimport binascii\\nfrom scipy.ndimage import label\\n\\nsequence = np.random.randint(0,2,1000).astype(np.uint8)\\ns = np.array2string(sequence, separator='',max_line_width=1000000)\\nn = int(s[1:-1], 2)\\nprint(s)\\nprint(n)\\n\\ns2 = sequence * 255\\nbinary_str = s2.tobytes()\\nprint(binary_str)\\n\\n\\n# Convert the binary string to an integer\\nint_val = int.from_bytes(binary_str, byteorder='big', signed=False)\\n#print(int.from_bytes(binary_str, byteorder='big', signed=False))\\n#print(int.from_bytes(binary_str, byteorder='little', signed=False))\\nprint(bin(int_val))\\n#sequence = (ellipseMask[:,100]/255).astype(np.uint8)\\n#print(sequence.shape)\\n\\n\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n a = changes_in_bitoperation(sequence)\\n end = time.time()\\n meanTime += end - start\\n\\nprint(a)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\\nsequence = sequence * 255\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n a = changes_in_bitoperation_v2(sequence)\\n end = time.time()\\n meanTime += end - start\\n\\nprint(a)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\\n\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n\\n flipCount = 0\\n\\n s = sequence.tobytes()\\n n = int.from_bytes(s, byteorder='big', signed=False)\\n mask = (1 << (len(s*8)-1)) - 1\\n\\n bitFlips = (n & mask) ^ (n >> 1)\\n\\n flipCount += bin(bitFlips).count('1')\\n if sequence[0] == 255:\\n flipCount += 1\\n end = time.time()\\n meanTime += end - start\\n \\n\\nprint(flipCount)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\""
]
},
"execution_count": 375,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# For debugging\n",
"# Generate a random array of 0s and 1s with length 10000 always with the same seed\n",
"'''\n",
"#np.random.seed(14)\n",
"import time\n",
"import binascii\n",
"from scipy.ndimage import label\n",
"\n",
"sequence = np.random.randint(0,2,1000).astype(np.uint8)\n",
"s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
"n = int(s[1:-1], 2)\n",
"print(s)\n",
"print(n)\n",
"\n",
"s2 = sequence * 255\n",
"binary_str = s2.tobytes()\n",
"print(binary_str)\n",
"\n",
"\n",
"# Convert the binary string to an integer\n",
"int_val = int.from_bytes(binary_str, byteorder='big', signed=False)\n",
"#print(int.from_bytes(binary_str, byteorder='big', signed=False))\n",
"#print(int.from_bytes(binary_str, byteorder='little', signed=False))\n",
"print(bin(int_val))\n",
"#sequence = (ellipseMask[:,100]/255).astype(np.uint8)\n",
"#print(sequence.shape)\n",
"\n",
"\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
" a = changes_in_bitoperation(sequence)\n",
" end = time.time()\n",
" meanTime += end - start\n",
"\n",
"print(a)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"\n",
"sequence = sequence * 255\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
" a = changes_in_bitoperation_v2(sequence)\n",
" end = time.time()\n",
" meanTime += end - start\n",
"\n",
"print(a)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"\n",
"\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
"\n",
" flipCount = 0\n",
"\n",
" s = sequence.tobytes()\n",
" n = int.from_bytes(s, byteorder='big', signed=False)\n",
" mask = (1 << (len(s*8)-1)) - 1\n",
"\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" flipCount += bin(bitFlips).count('1')\n",
" if sequence[0] == 255:\n",
" flipCount += 1\n",
" end = time.time()\n",
" meanTime += end - start\n",
" \n",
"\n",
"print(flipCount)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"'''\n"
]
},
{
"cell_type": "code",
"execution_count": 376,
"metadata": {},
"outputs": [],
"source": [
"def calcProjection(Np: int, centroid: np.ndarray, ellipseMask: np.ndarray) -> np.ndarray:\n",
" '''\n",
" Calculates the projection of the ellipse mask\n",
" :param Np: Number of pixels in the projection\n",
" :param centroid: Centroid of the ellipse mask\n",
" :param ellipseMask: Ellipse mask\n",
" :return: Projection of the ellipse mask\n",
" '''\n",
" xprojection = np.zeros(Np)\n",
" paddedMask = np.zeros((ellipseMask.shape[0],Np), np.uint8)\n",
"\n",
" if centroid[0]-Np/2 < 0 and centroid[0]+Np/2 < ellipseMask.shape[1]:\n",
" #Pad at the beginning\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroid[0]),0)), 'reflect')[:,0:Np]\n",
"\n",
" elif centroid[0]-Np/2 > 0 and centroid[0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(0,int(Np/2 - (ellipseMask.shape[1] - centroid[0])))), 'reflect')[:,0:Np]\n",
" elif centroid[0]-Np/2 < 0 and centroid[0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the beginning and at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroid[0]),int(Np/2 - (ellipseMask.shape[1] - centroid[0])))), 'reflect')[:,0:Np]\n",
" else:\n",
" #No padding\n",
" paddedMask = ellipseMask[:,int(centroid[0]-Np/2):int(centroid[0]+Np/2)]\n",
"\n",
" #Calculate the projection\n",
" for rowNumber in range(0,paddedMask.shape[1]):\n",
" row = paddedMask[:,rowNumber]\n",
" flipps = changes_in_bitoperation_v2(row)\n",
"\n",
" if row[0] > 0 and row[-1] == 0:\n",
" flipps += 1\n",
" elif row[-1] > 0 and row[0] == 0:\n",
" flipps += 1\n",
" elif row[0] > 0 and row[-1] > 0:\n",
" flipps += 2\n",
"\n",
" xprojection[rowNumber] = flipps/2\n",
"\n",
" return xprojection"
]
},
{
"cell_type": "code",
"execution_count": 377,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x200 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Iterate over each connected component\n",
"D = 32\n",
"Np = 256\n",
"kp = 5\n",
"epsilon = 3\n",
"\n",
"Vp = np.zeros((num_labels,D))\n",
"\n",
"angles = np.pi/32 * np.arange(0,D)\n",
"\n",
"height, width = ellipseMask.shape[:2] \n",
"# get the center coordinates of the image to create the 2D rotation matrix \n",
"center = (width/2, height/2) \n",
"\n",
"for angleNum in range(0,angles.shape[0]):\n",
" # Calculate the rotation matrix\n",
" #M = cv2.getRotationMatrix2D(center=center, angle=np.rad2deg(angles[angleNum]),scale=1)\n",
" #rotated = cv2.warpAffine(ellipseMask,M,(ellipseMask.shape[1],ellipseMask.shape[0]))\n",
" #rotated = ndimage.rotate(img, angles[angleNum], reshape=False)\n",
" #Threshold the rotated image\n",
" #ret, rotated = cv2.threshold(rotated, 127, 255, cv2.THRESH_BINARY)\n",
"\n",
" for centroidNum in range(100,101):#num_labels):\n",
" # Rotate ellipseMask around the centroid by angle\n",
" M = cv2.getRotationMatrix2D(center=(centroids[centroidNum,0],centroids[centroidNum,1]), angle=np.rad2deg(angles[angleNum]),scale=1)\n",
" rotated = cv2.warpAffine(ellipseMask,M,(ellipseMask.shape[1],ellipseMask.shape[0]))\n",
" #_, rotated = cv2.threshold(rotated, 127, 255, cv2.THRESH_BINARY)\n",
" rotated = (rotated/255).astype(np.uint8)*255\n",
" #print(centroids[centroidNum])\n",
" # Plot rotated ellipseMask\n",
" #plt.figure(figsize=(10,10))\n",
" #plt.imshow(rotated, cmap='gray')\n",
" #plt.show()\n",
"\n",
" # Rotate centroid by angle\n",
" rotated_centroid = np.dot(M,np.append(centroids[i],1))[:2]\n",
"\n",
" xprojection = calcProjection(Np, centroids[centroidNum] , rotated)\n",
"\n",
" #plot projection\n",
" #plt.figure(figsize=(10,2))\n",
" #plt.plot(xprojection)\n",
" #plt.show()\n",
"\n",
" #Check if xprojection is smaler or equal than 3 for all values\n",
" if np.all(xprojection <= 3):\n",
" Vp[centroidNum,angleNum] = epsilon\n",
" else:\n",
" # Calculate the rfft of the xprojection\n",
" dft = np.fft.rfft(xprojection)\n",
" #print(dft)\n",
"\n",
" #Check if dft[kp] is local maximum\n",
" if kp > 0 and kp < len(dft)-1:\n",
" if np.abs(dft[kp]) > np.abs(dft[kp-1]) and np.abs(dft[kp]) > np.abs(dft[kp+1]):\n",
" Vp[centroidNum,angleNum] = -np.log(np.abs(dft[kp])**2/np.abs(dft[0])**2)\n",
" else:\n",
" Vp[centroidNum,angleNum] = epsilon\n",
"\n",
" \n",
"#Plot Vp\n",
"plt.figure(figsize=(10,2))\n",
"plt.plot(angles,Vp[100,:])\n",
"plt.show()\n",
"\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
+437
View File
@@ -0,0 +1,437 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import argparse\n",
"import imutils\n",
"import cv2\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"import doxapy\n",
"import sys\n",
"import time\n",
"\n",
"inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/receipe-upload-_oqp9us3.jpg'\n",
"#inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/testbild.png'\n",
"img = cv2.imread(inputfile, cv2.IMREAD_GRAYSCALE)\n",
"start = 200\n",
"stop = start + 700\n",
"\n",
"img_snippet = img[start:stop,:]\n",
"img_copy = cv2.cvtColor(img_snippet,cv2.COLOR_GRAY2RGB)\n",
"\n",
"binary_image = np.empty(img_snippet.shape, img_snippet.dtype)\n",
"sauvola = doxapy.Binarization(doxapy.Binarization.Algorithms.ISAUVOLA)\n",
"sauvola.initialize(img_snippet)\n",
"sauvola.to_binary(binary_image, {\"window\": 45, \"k\": 0.009})\n",
"\n",
"#Plot the snippet\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(binary_image, cmap='gray')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"307\n"
]
}
],
"source": [
"#Invert the binary image\n",
"binary_image = cv2.bitwise_not(binary_image)\n",
"# Calc connected components\n",
"num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)\n",
"\n",
"# Calculate the mean vector and the covariance matrix of the pixels in each connected component\n",
"means = np.empty((num_labels,2))\n",
"covs = np.empty((num_labels,2,2))\n",
"eigenvalues = np.empty((num_labels,2))\n",
"eigenvectors = np.empty((num_labels,2,2))\n",
"\n",
"labelsForDelete = []\n",
"\n",
"for i in range(1,num_labels):\n",
" mask = np.zeros(binary_image.shape, np.uint8)\n",
" mask[labels == i] = 255\n",
" \n",
" xy_coords = np.flip(np.column_stack(np.where(mask == 255)), axis=1)\n",
" #means[i] = np.mean(xy_coords, axis=0) # Is equal to the centroid\n",
" covs[i] = np.cov(xy_coords, rowvar=False)\n",
"\n",
" # Calculate the eienvalues and eigenvectors of the covariance matrix\n",
" eigenvalues[i], eigenvectors[i] = np.linalg.eig(covs[i])\n",
"\n",
" #Sort the eigenvalues and eigenvectors\n",
" idx = eigenvalues[i].argsort()[::-1]\n",
" eigenvalues[i] = eigenvalues[i][idx]\n",
" eigenvectors[i] = eigenvectors[i][:,idx]\n",
"\n",
" #If eigenvalue1 / eigenvalue2 > 15, remove the corresponding connected component\n",
" if eigenvalues[i,0] / eigenvalues[i,1] > 15**2:\n",
" labelsForDelete.append(i)\n",
"\n",
"\n",
"#Delete the connected components in list\n",
"labels = np.delete(labels, labelsForDelete, axis=0)\n",
"num_labels = num_labels - len(labelsForDelete)\n",
"stats = np.delete(stats, labelsForDelete, axis=0)\n",
"centroids = np.delete(centroids, labelsForDelete, axis=0)\n",
"eigenvalues = np.delete(eigenvalues, labelsForDelete, axis=0)\n",
"eigenvectors = np.delete(eigenvectors, labelsForDelete, axis=0)\n",
"\n",
"# Create a new image with only the ellipses\n",
"ellipseMask = np.zeros(binary_image.shape, np.uint8)\n",
"for i in range(1,num_labels):\n",
" # Plot eigenvalues as ellipses in black and white image\n",
" cv2.ellipse(ellipseMask,(int(centroids[i,0]),int(centroids[i,1])),(int(np.sqrt(eigenvalues[i,0])),int(np.sqrt(eigenvalues[i,1]))),np.rad2deg(np.arctan2(eigenvectors[i,0,1],eigenvectors[i,0,0])),0,360,(255,255,255),-1)\n",
"\n",
"height, width = ellipseMask.shape[:2] \n",
"# get the center coordinates of the image to create the 2D rotation matrix \n",
"center = (width/2, height/2) \n",
"# Get diagonal of the image\n",
"diagonal = np.sqrt(width**2 + height**2)\n",
"\n",
"# Pad the ellipseMask with zeros to around the center to fit the diagonal\n",
"ellipseMask = np.pad(ellipseMask, ((int(diagonal/2 - height/2),int(diagonal/2 - height/2)),(int(diagonal/2 - width/2),int(diagonal/2 - width/2))), 'constant', constant_values=(0,0))\n",
"heightPadded, widthPadded = ellipseMask.shape[:2] \n",
"centerPadded = (widthPadded/2, heightPadded/2) \n",
"\n",
"# Shift centroids by padded amount\n",
"centroids = centroids + (diagonal/2 - width/2, diagonal/2 - height/2)\n",
"\n",
"print(num_labels)\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def changes_in_bitoperation(sequence: np.ndarray) -> int:\n",
" '''\n",
" Count the number of bit flips in a binary sequence (2x faster than itertools solution), adopten from: \n",
" https://stackoverflow.com/questions/70300297/is-there-a-built-in-python-function-to-count-bit-flip-in-a-binary-string#:~:text=There%20is%20a%20very%20fast%20way%20to%20do,string%20to%20count%20the%20number%20of%20bit%20flips.\n",
" :param sequence: A binary sequence as a numpy array\n",
" :return: The number of bit flips\n",
" '''\n",
" # Convert the sequence to an integer: [0,1,1,0,1] -> 0b01101\n",
" s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
" n = int(s[1:-1], 2)\n",
"\n",
" # Build a binary mask to skip the most significant bit of n: 0b01101 -> 0b01111\n",
" mask = (1 << (len(s)-1)) - 1\n",
"\n",
" # Check if the ith bit of n is different from the (i+1)th bit of n using a bit-wise XOR:\n",
" # 0b01101 & 0b01111 -> 0b1101 (discard the first bit)\n",
" # 0b01101 >> 1 -> 0b0110\n",
" # 0b1101 ^ 0b0110 -> 0b1011\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" # Convert the integer back to a string and count the bit flips: 0b1011 -> \"0b1011\" -> 3\n",
" flipCount = bin(bitFlips).count('1')\n",
" return flipCount"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def changes_in_bitoperation_v2(sequence: np.ndarray) -> int:\n",
" '''\n",
" Count the number of bit flips in a binary sequence (2x faster than itertools solution), adopten from: \n",
" https://stackoverflow.com/questions/70300297/is-there-a-built-in-python-function-to-count-bit-flip-in-a-binary-string#:~:text=There%20is%20a%20very%20fast%20way%20to%20do,string%20to%20count%20the%20number%20of%20bit%20flips.\n",
" :param sequence: A binary sequence as a numpy array\n",
" :return: The number of bit flips\n",
" '''\n",
" # Convert the sequence to an integer: [0,1,1,0,1] -> 0b01101\n",
" #s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
" # = int(s[1:-1], 2)\n",
" s = sequence.tobytes()\n",
" n = int.from_bytes(s, byteorder='big', signed=False)\n",
"\n",
" # Build a binary mask to skip the most significant bit of n: 0b01101 -> 0b01111\n",
" mask = (1 << (len(s)*8-1)) - 1\n",
"\n",
" # Check if the ith bit of n is different from the (i+1)th bit of n using a bit-wise XOR:\n",
" # 0b01101 & 0b01111 -> 0b1101 (discard the first bit)\n",
" # 0b01101 >> 1 -> 0b0110\n",
" # 0b1101 ^ 0b0110 -> 0b1011\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" # Convert the integer back to a string and count the bit flips: 0b1011 -> \"0b1011\" -> 3\n",
" flipCount = bin(bitFlips).count('1')\n",
" if sequence[0] == 255:\n",
" flipCount += 1\n",
" \n",
" return flipCount"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"\\n#np.random.seed(14)\\nimport time\\nimport binascii\\nfrom scipy.ndimage import label\\n\\nsequence = np.random.randint(0,2,1000).astype(np.uint8)\\ns = np.array2string(sequence, separator='',max_line_width=1000000)\\nn = int(s[1:-1], 2)\\nprint(s)\\nprint(n)\\n\\ns2 = sequence * 255\\nbinary_str = s2.tobytes()\\nprint(binary_str)\\n\\n\\n# Convert the binary string to an integer\\nint_val = int.from_bytes(binary_str, byteorder='big', signed=False)\\n#print(int.from_bytes(binary_str, byteorder='big', signed=False))\\n#print(int.from_bytes(binary_str, byteorder='little', signed=False))\\nprint(bin(int_val))\\n#sequence = (ellipseMask[:,100]/255).astype(np.uint8)\\n#print(sequence.shape)\\n\\n\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n a = changes_in_bitoperation(sequence)\\n end = time.time()\\n meanTime += end - start\\n\\nprint(a)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\\nsequence = sequence * 255\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n a = changes_in_bitoperation_v2(sequence)\\n end = time.time()\\n meanTime += end - start\\n\\nprint(a)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\\n\\nmeanTime = 0\\nfor i in range(0,1000):\\n start = time.time()\\n\\n flipCount = 0\\n\\n s = sequence.tobytes()\\n n = int.from_bytes(s, byteorder='big', signed=False)\\n mask = (1 << (len(s*8)-1)) - 1\\n\\n bitFlips = (n & mask) ^ (n >> 1)\\n\\n flipCount += bin(bitFlips).count('1')\\n if sequence[0] == 255:\\n flipCount += 1\\n end = time.time()\\n meanTime += end - start\\n \\n\\nprint(flipCount)\\nmeanTime = meanTime / 100\\nprint(meanTime)\\n\""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# For debugging\n",
"# Generate a random array of 0s and 1s with length 10000 always with the same seed\n",
"'''\n",
"#np.random.seed(14)\n",
"import time\n",
"import binascii\n",
"from scipy.ndimage import label\n",
"\n",
"sequence = np.random.randint(0,2,1000).astype(np.uint8)\n",
"s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
"n = int(s[1:-1], 2)\n",
"print(s)\n",
"print(n)\n",
"\n",
"s2 = sequence * 255\n",
"binary_str = s2.tobytes()\n",
"print(binary_str)\n",
"\n",
"\n",
"# Convert the binary string to an integer\n",
"int_val = int.from_bytes(binary_str, byteorder='big', signed=False)\n",
"#print(int.from_bytes(binary_str, byteorder='big', signed=False))\n",
"#print(int.from_bytes(binary_str, byteorder='little', signed=False))\n",
"print(bin(int_val))\n",
"#sequence = (ellipseMask[:,100]/255).astype(np.uint8)\n",
"#print(sequence.shape)\n",
"\n",
"\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
" a = changes_in_bitoperation(sequence)\n",
" end = time.time()\n",
" meanTime += end - start\n",
"\n",
"print(a)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"\n",
"sequence = sequence * 255\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
" a = changes_in_bitoperation_v2(sequence)\n",
" end = time.time()\n",
" meanTime += end - start\n",
"\n",
"print(a)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"\n",
"\n",
"meanTime = 0\n",
"for i in range(0,1000):\n",
" start = time.time()\n",
"\n",
" flipCount = 0\n",
"\n",
" s = sequence.tobytes()\n",
" n = int.from_bytes(s, byteorder='big', signed=False)\n",
" mask = (1 << (len(s*8)-1)) - 1\n",
"\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" flipCount += bin(bitFlips).count('1')\n",
" if sequence[0] == 255:\n",
" flipCount += 1\n",
" end = time.time()\n",
" meanTime += end - start\n",
" \n",
"\n",
"print(flipCount)\n",
"meanTime = meanTime / 100\n",
"print(meanTime)\n",
"'''\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def calcProjection(Np: int, centroid: np.ndarray, ellipseMask: np.ndarray) -> np.ndarray:\n",
" '''\n",
" Calculates the projection of the ellipse mask\n",
" :param Np: Number of pixels in the projection\n",
" :param centroid: Centroid of the ellipse mask\n",
" :param ellipseMask: Ellipse mask\n",
" :return: Projection of the ellipse mask\n",
" '''\n",
" xprojection = np.zeros(Np)\n",
" paddedMask = np.zeros((ellipseMask.shape[0],Np), np.uint8)\n",
"\n",
" if centroid[0]-Np/2 < 0 and centroid[0]+Np/2 < ellipseMask.shape[1]:\n",
" #Pad at the beginning\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroid[0]),0)), 'reflect')[:,0:Np]\n",
"\n",
" elif centroid[0]-Np/2 > 0 and centroid[0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(0,int(Np/2 - (ellipseMask.shape[1] - centroid[0])))), 'reflect')[:,0:Np]\n",
" elif centroid[0]-Np/2 < 0 and centroid[0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the beginning and at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroid[0]),int(Np/2 - (ellipseMask.shape[1] - centroid[0])))), 'reflect')[:,0:Np]\n",
" else:\n",
" #No padding\n",
" paddedMask = ellipseMask[:,int(centroid[0]-Np/2):int(centroid[0]+Np/2)]\n",
"\n",
" #Calculate the projection\n",
" for rowNumber in range(0,paddedMask.shape[1]):\n",
" row = paddedMask[:,rowNumber]\n",
" flipps = changes_in_bitoperation_v2(row)\n",
"\n",
" if row[0] > 0 and row[-1] == 0:\n",
" flipps += 1\n",
" elif row[-1] > 0 and row[0] == 0:\n",
" flipps += 1\n",
" elif row[0] > 0 and row[-1] > 0:\n",
" flipps += 2\n",
"\n",
" xprojection[rowNumber] = flipps/2\n",
"\n",
" return xprojection"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x200 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Iterate over each connected component\n",
"D = 32\n",
"Np = 256\n",
"kp = 5\n",
"epsilon = 3\n",
"\n",
"Vp = np.zeros((num_labels,D))\n",
"\n",
"angles = np.pi/32 * np.arange(0,D)\n",
"\n",
"for angleNum in range(0,angles.shape[0]):\n",
" # Calculate the rotation matrix\n",
" M = cv2.getRotationMatrix2D(center=centerPadded, angle=np.rad2deg(angles[angleNum]),scale=1)\n",
" rotated = cv2.warpAffine(ellipseMask,M,(ellipseMask.shape[1],ellipseMask.shape[0]))\n",
" #Rotate all centroids by angle\n",
" rotated_centroids = np.dot(M,np.append(centroids, np.ones((num_labels,1)), axis=1).T).T[:,:2]\n",
"\n",
" _, rotated = cv2.threshold(rotated, 127, 255, cv2.THRESH_BINARY)\n",
"\n",
" for centroidNum in range(100,101):#,num_labels):\n",
" #start = time.time()\n",
" xprojection = calcProjection(Np, rotated_centroids[centroidNum] , rotated)\n",
" #end = time.time()\n",
" #print(end-start)\n",
"\n",
" #start = time.time()\n",
" #Check if xprojection is smaler or equal than 3 for all values\n",
" if np.all(xprojection <= 3):\n",
" Vp[centroidNum,angleNum] = epsilon\n",
" else:\n",
" # Calculate the rfft of the xprojection\n",
" dft = np.fft.rfft(xprojection)\n",
" #print(dft)\n",
"\n",
" #Check if dft[kp] is local maximum\n",
" if kp > 0 and kp < len(dft)-1:\n",
" if np.abs(dft[kp]) > np.abs(dft[kp-1]) and np.abs(dft[kp]) > np.abs(dft[kp+1]):\n",
" Vp[centroidNum,angleNum] = -np.log(np.abs(dft[kp])**2/np.abs(dft[0])**2)\n",
" else:\n",
" Vp[centroidNum,angleNum] = epsilon\n",
" #stop = time.time()\n",
" #print(stop-start)\n",
"\n",
" \n",
"#Plot Vp\n",
"plt.figure(figsize=(10,2))\n",
"plt.plot(angles,Vp[100,:])\n",
"plt.show()\n",
"\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
+377
View File
@@ -0,0 +1,377 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 159,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import argparse\n",
"import imutils\n",
"import cv2\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"import doxapy\n",
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 172,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/receipe-upload-_oqp9us3.jpg'\n",
"#inputfile = '/home/elena/Documents/Projects/kassenzettel-django-react/testings/testbild.png'\n",
"img = cv2.imread(inputfile, cv2.IMREAD_GRAYSCALE)\n",
"start = 200\n",
"stop = start + 700\n",
"\n",
"img_snippet = img[start:stop,:]\n",
"img_copy = cv2.cvtColor(img_snippet,cv2.COLOR_GRAY2RGB)\n",
"\n",
"binary_image = np.empty(img_snippet.shape, img_snippet.dtype)\n",
"sauvola = doxapy.Binarization(doxapy.Binarization.Algorithms.ISAUVOLA)\n",
"sauvola.initialize(img_snippet)\n",
"sauvola.to_binary(binary_image, {\"window\": 45, \"k\": 0.009})\n",
"\n",
"\n",
"#Plot the snippet\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(binary_image, cmap='gray')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 176,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#Invert the binary image\n",
"binary_image = cv2.bitwise_not(binary_image)\n",
"# Calc connected components\n",
"num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)\n",
"\n",
"# Plot centers and bounding boxes of connected components in the snippet\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(img_copy, cmap='gray')\n",
"for i in range(70,71):#range(1,num_labels):\n",
" x = stats[i, cv2.CC_STAT_LEFT]\n",
" y = stats[i, cv2.CC_STAT_TOP]\n",
" w = stats[i, cv2.CC_STAT_WIDTH]\n",
" h = stats[i, cv2.CC_STAT_HEIGHT]\n",
" cx = centroids[i,0]\n",
" cy = centroids[i,1]\n",
" # Plot bounding box as rectangle\n",
" plt.plot([x,x+w],[y,y],'r-')\n",
" plt.plot([x,x],[y,y+h],'r-')\n",
" plt.plot([x,x+w],[y+h,y+h],'r-')\n",
" plt.plot([x+w,x+w],[y,y+h],'r-')\n",
"\n",
" # Plot center as cross\n",
" plt.plot([cx-5,cx+5],[cy,cy],'g-')\n",
" plt.plot([cx,cx],[cy-5,cy+5],'g-')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 170,
"metadata": {},
"outputs": [
{
"ename": "IndexError",
"evalue": "boolean index did not match indexed array along dimension 0; dimension is 700 but corresponding boolean dimension is 699",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb Cell 4\u001b[0m line \u001b[0;36m1\n\u001b[1;32m <a href='vscode-notebook-cell:/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb#W3sZmlsZQ%3D%3D?line=10'>11</a>\u001b[0m \u001b[39mfor\u001b[39;00m i \u001b[39min\u001b[39;00m \u001b[39mrange\u001b[39m(\u001b[39m1\u001b[39m,num_labels):\n\u001b[1;32m <a href='vscode-notebook-cell:/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb#W3sZmlsZQ%3D%3D?line=11'>12</a>\u001b[0m mask \u001b[39m=\u001b[39m np\u001b[39m.\u001b[39mzeros(binary_image\u001b[39m.\u001b[39mshape, np\u001b[39m.\u001b[39muint8)\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb#W3sZmlsZQ%3D%3D?line=12'>13</a>\u001b[0m mask[labels \u001b[39m==\u001b[39;49m i] \u001b[39m=\u001b[39m \u001b[39m255\u001b[39m\n\u001b[1;32m <a href='vscode-notebook-cell:/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb#W3sZmlsZQ%3D%3D?line=14'>15</a>\u001b[0m xy_coords \u001b[39m=\u001b[39m np\u001b[39m.\u001b[39mflip(np\u001b[39m.\u001b[39mcolumn_stack(np\u001b[39m.\u001b[39mwhere(mask \u001b[39m==\u001b[39m \u001b[39m255\u001b[39m)), axis\u001b[39m=\u001b[39m\u001b[39m1\u001b[39m)\n\u001b[1;32m <a href='vscode-notebook-cell:/home/elena/Documents/Projects/kassenzettel-django-react/testings/linedetection_paper.ipynb#W3sZmlsZQ%3D%3D?line=15'>16</a>\u001b[0m \u001b[39m#means[i] = np.mean(xy_coords, axis=0) # Is equal to the centroid\u001b[39;00m\n",
"\u001b[0;31mIndexError\u001b[0m: boolean index did not match indexed array along dimension 0; dimension is 700 but corresponding boolean dimension is 699"
]
}
],
"source": [
"# Calculate the mean vector and the covariance matrix of the pixels in each connected component\n",
"means = np.empty((num_labels,2))\n",
"covs = np.empty((num_labels,2,2))\n",
"eigenvalues = np.empty((num_labels,2))\n",
"eigenvectors = np.empty((num_labels,2,2))\n",
"\n",
"img_copy = cv2.cvtColor(img_snippet,cv2.COLOR_GRAY2RGB)\n",
"\n",
"labelsForDelete = []\n",
"\n",
"for i in range(1,num_labels):\n",
" mask = np.zeros(binary_image.shape, np.uint8)\n",
" mask[labels == i] = 255\n",
" \n",
" xy_coords = np.flip(np.column_stack(np.where(mask == 255)), axis=1)\n",
" #means[i] = np.mean(xy_coords, axis=0) # Is equal to the centroid\n",
" covs[i] = np.cov(xy_coords, rowvar=False)\n",
"\n",
" # Calculate the eienvalues and eigenvectors of the covariance matrix\n",
" eigenvalues[i], eigenvectors[i] = np.linalg.eig(covs[i])\n",
"\n",
" #Sort the eigenvalues and eigenvectors\n",
" idx = eigenvalues[i].argsort()[::-1]\n",
" eigenvalues[i] = eigenvalues[i][idx]\n",
" eigenvectors[i] = eigenvectors[i][:,idx]\n",
"\n",
" #If eigenvalue1 / eigenvalue2 > 15, remove the corresponding connected component\n",
" if eigenvalues[i,0] / eigenvalues[i,1] > 15**2:\n",
" labelsForDelete.append(i)\n",
"\n",
"\n",
"#Delete the connected components in list\n",
"labels = np.delete(labels, labelsForDelete, axis=0)\n",
"num_labels = num_labels - len(labelsForDelete)\n",
"stats = np.delete(stats, labelsForDelete, axis=0)\n",
"centroids = np.delete(centroids, labelsForDelete, axis=0)\n",
"eigenvalues = np.delete(eigenvalues, labelsForDelete, axis=0)\n",
"eigenvectors = np.delete(eigenvectors, labelsForDelete, axis=0)\n",
"\n",
"# Plot eigenvectors and eigenvalues as ellipses\n",
"plt.figure(figsize=(10,10))\n",
"print(num_labels)\n",
"for i in range(1,num_labels):\n",
" cx = centroids[i,0]\n",
" cy = centroids[i,1]\n",
" \n",
" # Plot eigenvalues as ellipses\n",
" cv2.ellipse(img_copy,(int(centroids[i,0]),int(centroids[i,1])),(int(np.sqrt(eigenvalues[i,0])),int(np.sqrt(eigenvalues[i,1]))),np.rad2deg(np.arctan2(eigenvectors[i,0,1],eigenvectors[i,0,0])),0,360,(0,255,0),2)\n",
"plt.imshow(img_copy, cmap='gray')\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": 143,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Create a new image with only the ellipses\n",
"ellipseMask = np.zeros(binary_image.shape, np.uint8)\n",
"for i in range(1,num_labels):\n",
" # Plot eigenvalues as ellipses in black and white image\n",
" cv2.ellipse(ellipseMask,(int(centroids[i,0]),int(centroids[i,1])),(int(np.sqrt(eigenvalues[i,0])),int(np.sqrt(eigenvalues[i,1]))),np.rad2deg(np.arctan2(eigenvectors[i,0,1],eigenvectors[i,0,0])),0,360,(255,255,255),-1)\n",
"\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(ellipseMask, cmap='gray')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 153,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[661.46630728 60.69811321]\n",
"(700, 256)\n"
]
},
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 400x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1000x200 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Project the ellipses to the x-axis\n",
"#for n in range(0,ellipseMask.shape[0]):\n",
"# s = ellipseMask[n,:].tostring()\n",
"# print(s)\n",
"from itertools import groupby \n",
"\n",
"#Itertools solution\n",
"def changes_in(sequence):\n",
" return len(list(groupby(sequence))) - 1\n",
"\n",
"#Bitwise solution: Ruffly 2 times faster than itertools solution\n",
"#https://stackoverflow.com/questions/70300297/is-there-a-built-in-python-function-to-count-bit-flip-in-a-binary-string#:~:text=There%20is%20a%20very%20fast%20way%20to%20do,string%20to%20count%20the%20number%20of%20bit%20flips.\n",
"def changes_in_bitoperation(sequence):\n",
" # Convert the sequence to an integer: [0,1,1,0,1] -> 0b01101\n",
" s = np.array2string(sequence, separator='',max_line_width=1000000)\n",
" n = int(s[1:-1], 2)\n",
"\n",
" # Build a binary mask to skip the most significant bit of n: 0b01101 -> 0b01111\n",
" mask = (1 << (len(s)-1)) - 1\n",
"\n",
" # Check if the ith bit of n is different from the (i+1)th bit of n using a bit-wise XOR:\n",
" # 0b01101 & 0b01111 -> 0b1101 (discard the first bit)\n",
" # 0b01101 >> 1 -> 0b0110\n",
" # 0b1101 ^ 0b0110 -> 0b1011\n",
" bitFlips = (n & mask) ^ (n >> 1)\n",
"\n",
" # Convert the integer back to a string and count the bit flips: 0b1011 -> \"0b1011\" -> 3\n",
" flipCount = bin(bitFlips).count('1')\n",
" return flipCount\n",
"\n",
"Np = 256\n",
"\n",
"xprojection = np.zeros(Np)\n",
"\n",
"centroidNum = 7\n",
"print(centroids[centroidNum,:])\n",
"\n",
"paddedMask = np.zeros((ellipseMask.shape[0],Np), np.uint8)\n",
"\n",
"if centroids[centroidNum,0]-Np/2 < 0 and centroids[centroidNum,0]+Np/2 < ellipseMask.shape[1]:\n",
" #Pad at the beginning\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroids[centroidNum,0]),0)), 'reflect')[:,0:Np]\n",
" print(paddedMask.shape)\n",
"\n",
"elif centroids[centroidNum,0]-Np/2 > 0 and centroids[centroidNum,0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(0,int(Np/2 - (ellipseMask.shape[1] - centroids[centroidNum,0])))), 'reflect')[:,0:Np]\n",
"elif centroids[centroidNum,0]-Np/2 < 0 and centroids[centroidNum,0]+Np/2 > ellipseMask.shape[1]:\n",
" #Pad at the beginning and at the end\n",
" paddedMask = np.pad(ellipseMask, ((0,0),(int(Np/2 - centroids[centroidNum,0]),int(Np/2 - (ellipseMask.shape[1] - centroids[centroidNum,0])))), 'reflect')[:,0:Np]\n",
"else:\n",
" #No padding\n",
" paddedMask = ellipseMask[:,int(centroids[centroidNum,0]-Np/2):int(centroids[centroidNum,0]+Np/2)]\n",
" print(paddedMask.shape)\n",
"\n",
"#plot paddedMask\n",
"plt.figure(figsize=(4,4))\n",
"plt.imshow(paddedMask, cmap='gray')\n",
"plt.show()\n",
"\n",
"\n",
"for rowNumber in range(0,paddedMask.shape[1]):\n",
" row = (paddedMask[:,rowNumber]/255).astype(np.uint8)\n",
" flipps = changes_in_bitoperation(row)\n",
" if row[0] > 0 and row[-1] == 0:\n",
" flipps += 1\n",
" elif row[-1] > 0 and row[0] == 0:\n",
" flipps += 1\n",
" elif row[0] > 0 and row[-1] > 0:\n",
" flipps += 2\n",
"\n",
" xprojection[rowNumber] = flipps/2\n",
"\n",
"#Plot the xprojection as line chart\n",
"plt.figure(figsize=(10,2))\n",
"plt.plot(xprojection)\n",
"plt.show()\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 152,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"kp is not local maximum\n",
"0.01\n"
]
}
],
"source": [
"epsilon = 0.01\n",
"kp = 5\n",
"\n",
"Vp = 0\n",
"#Check if xprojection is smaler or equal than 3 for all values\n",
"if np.all(xprojection <= 3):\n",
" Vp = epsilon\n",
"else:\n",
" # Calculate the rfft of the xprojection\n",
" dft = np.fft.rfft(xprojection)\n",
" #print(dft)\n",
"\n",
" #Check if dft[kp] is local maximum\n",
" if kp > 0 and kp < len(dft)-1:\n",
" if np.abs(dft[kp]) > np.abs(dft[kp-1]) and np.abs(dft[kp]) > np.abs(dft[kp+1]):\n",
" Vp = -np.log(np.abs(dft[kp])**2/np.abs(dft[0])**2)\n",
" else:\n",
" Vp = epsilon\n",
" print(\"kp is not local maximum\")\n",
"\n",
"print(Vp)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 668 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB