{"id":16751013,"url":"https://github.com/elerac/polanalyser","last_synced_at":"2025-04-12T21:19:48.796Z","repository":{"id":39746924,"uuid":"225809950","full_name":"elerac/polanalyser","owner":"elerac","description":"Polarization image analysis tool. Demosaicing, Stokes vector, Mueller matrix.","archived":false,"fork":false,"pushed_at":"2025-02-08T07:38:40.000Z","size":24417,"stargazers_count":174,"open_issues_count":0,"forks_count":27,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T21:19:31.750Z","etag":null,"topics":["demosaicing","mueller-matrix","polarization","polarization-imaging","python","stokes-vector"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elerac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-04T07:51:24.000Z","updated_at":"2025-04-09T03:25:32.000Z","dependencies_parsed_at":"2024-06-01T13:53:36.962Z","dependency_job_id":"374f6160-5b0c-473e-af99-7b6e6ae54f34","html_url":"https://github.com/elerac/polanalyser","commit_stats":{"total_commits":212,"total_committers":2,"mean_commits":106.0,"dds":"0.061320754716981174","last_synced_commit":"181c8afeed15268a427f8924c51ebe94084619f0"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elerac%2Fpolanalyser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elerac%2Fpolanalyser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elerac%2Fpolanalyser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elerac%2Fpolanalyser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elerac","download_url":"https://codeload.github.com/elerac/polanalyser/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248632119,"owners_count":21136629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["demosaicing","mueller-matrix","polarization","polarization-imaging","python","stokes-vector"],"created_at":"2024-10-13T02:42:50.122Z","updated_at":"2025-04-12T21:19:48.767Z","avatar_url":"https://github.com/elerac.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg alt=\"polanalyser logo\" src=\"documents/polanalyser_logo.png\" height=\"90em\"\u003e\n\u003c/p\u003e\n\n---\n\nPolanalyser is polarization image analysis tool.\n\n## Key Features\n\n- [**Demosaicing for polarimetric image sensor**](#polarization-demosaicing)\n  - Both Monochrome/Color Polarization image sensors (*e.g.*, IMX250MZR / MYR) are supported.\n- [**Analysis of Stokes vector**](#analysis-of-stokes-vector)\n  - Obtain Stokes vector from images captured with a polarization camera or custom setup.\n  - Convert Stokes vector to meaningful parameters, such as DoLP, AoLP.\n- [**Analysis of Mueller matrix**](#analysis-of-mueller-matrix)\n  - Provide basic Mueller matrix elements, such as polarizer, retarder, and rotator.\n  - Obtain Mueller matrix from images captured under a variety of polarimetric conditions by using a least-squares method.\n- [**Visualizing polarimetric images**](#visualizing-polarimetric-images)\n  - Apply colormap to polarization images, such as DoLP, AoLP, ToP, and CoP.\n  - Visualize the Mueller matrix image in grid form.\n- [**Symbolic Stokes-Mueller computation**](#symbolic-stokes-mueller-computation)\n  - Symbolic calculation of the Stokes vector and Mueller matrix to understand complex combinations of optical elements.\n\n## Dependencies and Installation\n\n- Numpy\n- OpenCV\n- matplotlib\n- SymPy (optional)\n\n```sh\npip install polanalyser\n```\n\n## Polarization Image Dataset\n\nDataset of images captured by a polarization camera (FLIR, BFS-U3-51S5P-C) is available. You can use these images to learn how to analyze polarization images.\n\n[**[Click here to download the dataset (Google Drive)]**](https://drive.google.com/drive/folders/1vCe9N05to5_McvwyDqxTmLIKz7vRzmbX?usp=sharing)\n\n[![](documents/dataset_overview.png)](https://drive.google.com/drive/folders/1vCe9N05to5_McvwyDqxTmLIKz7vRzmbX?usp=sharing)\n\n## Usage\n\n### Polarization demosaicing\n\nDemosaic raw polarization image captured with a polarization sensor (*e.g.*, [IMX250MZR / MYR](https://www.sony-semicon.com/en/products/is/industry/polarization.html)).\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"documents/demosaicing_dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"documents/demosaicing_light.png\"\u003e\n  \u003cimg alt=\"demosaicing\" src=\"documents/demosaicing_light.png\"\u003e\n\u003c/picture\u003e\n\n```python\nimport cv2\nimport polanalyser as pa\n\nimg_raw = cv2.imread(\"dataset/dragon.png\", 0)\n\nimg_000, img_045, img_090, img_135 = pa.demosaicing(img_raw, pa.COLOR_PolarMono)\n# img_000, img_045, img_090, img_135 = pa.demosaicing(img_raw, pa.COLOR_PolarRGB)\n```\n\n### Analysis of Stokes vector\n\n[**Stokes vector**](https://en.wikipedia.org/wiki/Stokes_parameters) describes the polarization states. We can measure these values by using a *linear polarizer* (To measure the circular polarization $s_3$, we also need to use a *retarder*).\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"documents/stokes_setup_dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"documents/stokes_setup_light.png\"\u003e\n  \u003cimg alt=\"Stokes setup\" src=\"documents/stokes_setup_light.png\"\u003e\n\u003c/picture\u003e\n\nStokes vector can be converted to meaningful values. *Degree of Linear Polarization* (DoLP) represents how much the light is polarized. The value is 1 for perfectly polarized light and 0 for unpolarized light. *Angle of Linear Polarization* (AoLP) represents the polarization angle of the incident light relative to the camera sensor axis. The value ranges from 0 to 180 degrees.\n\n```python\nimport cv2\nimport numpy as np\nimport polanalyser as pa\n\n# Read image and demosaicing\nimg_raw = cv2.imread(\"dataset/dragon.png\", 0)\nimg_000, img_045, img_090, img_135 = pa.demosaicing(img_raw, pa.COLOR_PolarMono)\n\n# Calculate the Stokes vector per-pixel\nimage_list = [img_000, img_045, img_090, img_135]\nangles = np.deg2rad([0, 45, 90, 135])\nimg_stokes = pa.calcStokes(image_list, angles)\n\n# Decompose the Stokes vector into its components\nimg_s0, img_s1, img_s2 = cv2.split(img_stokes)\n\n# Convert the Stokes vector to Intensity, DoLP and AoLP\nimg_intensity = pa.cvtStokesToIntensity(img_stokes)\nimg_dolp = pa.cvtStokesToDoLP(img_stokes)\nimg_aolp = pa.cvtStokesToAoLP(img_stokes)\n```\n\n||Example of results | |\n|:-:|:-:|:-:|\n|Intensity (s0)|DoLP|AoLP|\n|![](documents/dragon_IMX250MZR_intensity.jpg)|![](documents/dragon_IMX250MZR_DoLP.jpg)|![](documents/dragon_IMX250MZR_AoLP.jpg)|\n\n### Analysis of Mueller matrix\n\n[**Mueller matrix**](https://en.wikipedia.org/wiki/Mueller_calculus) represents the change of the polarization state of light. The matrix size is 4x4 (When we consider only linear polarization, the size is 3x3).\n\nPolanalyzer provides basic Mueller matrix elements in numpy array. For example, the following code shows the Mueller matrix of a linear polarizer and a quarter-wave plate.\n\n```python\nimport polanalyser as pa\n\n# Linear polarizer\nM_LP = pa.polarizer(0)\nprint(M_LP)\n# [[0.5 0.5 0.  0. ]\n#  [0.5 0.5 0.  0. ]\n#  [0.  0.  0.  0. ]\n#  [0.  0.  0.  0. ]]\n\n# Quarter-wave plate\nM_QWP = pa.qwp(0)\nprint(M_QWP)\n# [[ 1.  0.  0.  0.]\n#  [ 0.  1.  0.  0.]\n#  [ 0.  0.  0.  1.]\n#  [ 0.  0. -1.  0.]]\n```\n\nWe can measure the unknown Mueller matrix by changing the polarization state of both the light and the detector (a.k.a. ellipsometry). The following figure shows a schematic diagram to measure the unknown Mueller matrix $`\\mathbf{M}`$\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"documents/mueller_setup_dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"documents/mueller_setup_light.png\"\u003e\n  \u003cimg alt=\"Mueller setup\" src=\"documents/mueller_setup_light.png\"\u003e\n\u003c/picture\u003e\n\n$I$ denotes the intensity of the unpolarized light source. $`\\mathbf{M}_\\textrm{PSG}`$ and $`\\mathbf{M}_\\textrm{PSA}`$ represent the Polarization state generator and analyzer (PSG and PSA) in Mueller matrix form. PSG and PSA are commonly composed of the basic optical elements (i.e., linear polarizer and retarder).\nThe detector measures the intensity $f$ expressed by $`f = [ \\mathbf{M}_\\textrm{PSA} \\mathbf{M} \\mathbf{M}_\\textrm{PSG} I]_{00}`$. $[...]_{00}$ extracts the (0, 0) component of the matrix.\n\nMeasuring $f$ by changing many combinations of $`\\mathbf{M}_\\textrm{PSG}`$ and $`\\mathbf{M}_\\textrm{PSA}`$ can estimate the unknown Mueller matrix $`\\mathbf{M}`$ with a linear least-squares method.\n\nThe following code shows the example to estimate the 3x3 Mueller matrix image.\n\n```python\nimport polanalyser as pa\n\n# Read 16 images and Mueller matrices of PSG and PSA\nfilepath = \"dataset/toy_example_3x3_pc\"\nimages, props = pa.imreadMultiple(filepath)\nprint(images.shape)  # (16, 2048, 2448)\nmm_psg = props[\"mueller_psg\"] # (16, 3, 3)\nmm_psa = props[\"mueller_psa\"] # (16, 3, 3)\n\n# Calculate Mueller matrix image\nimg_mueller = pa.calcMueller(images, mm_psg, mm_psa)\nprint(img_mueller.shape)  # (2048, 2448, 3, 3)\n```\n\n![](documents/mueller_various.jpg)\n\n\n### Visualizing polarimetric images\n\n### Stokes vector visualization\n\nPolanalyser provides functions to visualize Stokes vector images, such as AoLP, DoLP, ToP (Type of Polarization), and CoP (Chirality of Polarization). The color mapping is designed based on the relevant papers [[Wilkie and Weidlich, SCCG2010]](https://dl.acm.org/doi/10.1145/1925059.1925070), [[Baek+, SIGGRAPH2020]](http://vclab.kaist.ac.kr/siggraph2020/index.html), [[Jeon+, CVPR2024]](https://eschoi.com/SPDataset/). Note that this mapping is slightly different from the original papers.\n\n```python\n# Example of visualization functions\nimg_aolp_vis = pa.applyColorToAoLP(img_aolp)\nimg_dolp_vis = pa.applyColorToDoP(img_dolp)\nimg_top_vis = pa.applyColorToToP(img_ellipticity_angle, img_dop)\nimg_cop_vis = pa.applyColorToCoP(img_ellipticity_angle)\n```\n\nHere is an example of visualizing the Stokes vector images. The stokes image is borrowed from the spectro-polarimetric dataset [[Jeon+, CVPR2024]](https://huggingface.co/datasets/jyj7913/spectro-polarimetric).\n\n|||||\n|:-:|:-:|:-:|:-:|\n| s0 | s1 | s2 | s3 |\n|![](documents/visualization/color.jpeg)|![](documents/visualization/s1.jpeg)|![](documents/visualization/s2.jpeg)|![](documents/visualization/s3.jpeg)|\n| DoLP | AoLP | AoLP (light) | AoLP (dark) |\n|![](documents/visualization/dolp.jpeg)|![](documents/visualization/aolp.jpeg)|![](documents/visualization/aolp_light.jpeg)|![](documents/visualization/aolp_dark.jpeg)|\n| DoP | DoCP | ToP | CoP |\n|![](documents/visualization/dop.jpeg)|![](documents/visualization/docp.jpeg)|![](documents/visualization/top.jpeg)|![](documents/visualization/cop.jpeg)|\n\nIn AoLP visualization, Polanalyser provides three types of AoLP visualization: AoLP, AoLP (light), and AoLP (dark). For more details, [see the wiki page](https://github.com/elerac/polanalyser/wiki/How-to-Visualizing-the-AoLP-Image).\n\n### Mueller matrix visualization\n\nPolanalyser provides functions to apply a colormap and make a 3x3 or 4x4 grid to visualize the Mueller matrix image.\n\nBefore visualizing the Mueller matrix image, we need to normalize the Mueller matrix. Here are three possible options, each with pros and cons. You need to choose the appropriate normalization method according to the purpose of the visualization and the chosen colormap.\n\n```python\n# Normalize Mueller matrix image\n# img_mueller: (H, W, 3, 3)\n\n# Option 1: Normalize by the maximum value\n# Pros: Show values linearly\n# Cons: The small values may not be visible\nimg_mueller_maxnorm = img_mueller / np.abs(img_mueller).max()  \n\n# Option 2: Gamma correction\n# Pros: Enhance the small values\n# Cons: The large values become saturated\nimg_mueller_gamma = pa.gammaCorrection(img_mueller_maxnorm)  \n\n# Option 3: m00 norm (scale by m00 value of each pixel)\n# Pros: Visualizes polarization components ratio independently of the intensity\n# Cons: m00 becomes 1, and cannot represent the absolute intensity\nimg_mueller_m00norm = img_mueller / img_mueller[..., 0, 0][..., None, None]  \n```\n\nAfter normalizing the Mueller matrix image, we can apply a colormap and make a grid to visualize the Mueller matrix image.\n\n```python\n# Apply colormap and make grid\nimg_mueller_norm_vis = pa.applyColorMap(img_mueller_maxnorm, \"RdBu\", -1, 1)  # (H, W, 3, 3, 3)\nimg_mueller_norm_vis_grid = pa.makeGridMueller(img_mueller_maxnorm_vis) # (H*3, W*3, 3)\n```\n\n| Max norm | Max norm + Gamma | m00 norm |\n|:--------------:|:--------------:|:--------------:|\n|![](documents/visualization/mueller_maxnorm_vis_grid.jpeg)|![](documents/visualization/mueller_gamma_vis_grid.jpeg)|![](documents/visualization/mueller_m00norm_vis_grid.jpeg)|\n\n### Symbolic Stokes-Mueller computation\n\nThis feature supports the symbolic computation of the Stokes vector and Mueller matrix powered by SymPy. This feature is particularly useful for understanding the effects of complex combinations of optical elements. \n\nHere are examples of Malus's law and an ellipsometer. We can symbolically obtain the intensity of light passing through the sequence of optical elements without tedious calculations by hand.\n\n```python\nfrom sympy import symbols, simplify\nimport polanalyser.sympy as pas\n\ntheta = symbols(\"theta\", real=True)\n\n# Example 1: Malus's law\nM_L1 = pas.polarizer(0)\nM_L2 = pas.polarizer(theta)\nf = (M_L2 @ M_L1)[0, 0]  \nprint(simplify(f))  \n# 0.5*cos(theta)**2\n\n# Example 2: Ellipsometer [Azzam+, 1978][Baek+, 2020]\nM = pas.mueller()  # Symbolic Mueller matrix\nI = 1.0\nM_PSG = pas.qwp(theta) @ pas.polarizer(0)\nM_PSA = pas.polarizer(0) @ pas.qwp(5 * theta)\nf = (M_PSA @ M @ M_PSG * I)[0, 0] \nprint(simplify(f))  \n# 0.25*m00 + 0.25*m10*cos(10*theta)**2 + 0.125*m20*sin(20*theta) - 0.25*m30*sin(10*theta) + 0.25*(m01 + m11*cos(10*theta)**2 + m21*sin(20*theta)/2 - m31*sin(10*theta))*cos(2*theta)**2 + 0.25*(m02 + m12*cos(10*theta)**2 + m22*sin(20*theta)/2 - m32*sin(10*theta))*sin(2*theta)*cos(2*theta) + 0.25*(m03 + m13*cos(10*theta)**2 + m23*sin(20*theta)/2 - m33*sin(10*theta))*sin(2*theta)\n```\n\n## Notations\n\nPlease refer to the [notations.md](documents/notations.md) for the definition of the Stokes vector and Mueller matrix used in Polanalyser.\n\n\n## Citation\n\nIf you find Polanalyser useful, please consider citing as follows:\n\n```bibtex\n@software{maeda2019polanalyser,\n  author = {Ryota Maeda},\n  title = {Polanalyser: Polarization Image Analysis Tool},\n  url = {https://github.com/elerac/polanalyser},\n  year = {2019},\n}\n```\n\n## Related Project\n\nIf you like Polanalyser, you are also interested in the following paper.\n\n- Ryota Maeda, Shinsaku Hiura, **Polarimetric Light Transport Analysis for Specular Inter-reflection**,  IEEE Transactions on Computational Imaging, 2024. [[Project Page]](https://elerac.github.io/projects/PolarimetricInterreflection/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felerac%2Fpolanalyser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felerac%2Fpolanalyser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felerac%2Fpolanalyser/lists"}