diff --git a/CITATION.cff b/CITATION.cff index 12dcb16..342fc11 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -5,11 +5,13 @@ authors: orcid: 0000-0003-0142-8597 - name: Ronan Docherty orcid: 0000-0002-7332-0924 + - name: Steve Kench + orcid: 0000-0002-7263-6724 - name: Samuel J. Cooper orcid: 0000-0003-4055-6903 -title: "Predicting Microstructural Representativity from a Single Image" +title: "Prediction of Microstructural Representativity from a Single Image" doi: ARXIV_DOI -url: "https://github.com/tldr-group/Representativity" +url: "https://github.com/tldr-group/ImageRep" preferred-citation: type: article authors: @@ -17,10 +19,12 @@ preferred-citation: orcid: 0000-0003-0142-8597 - name: Ronan Docherty orcid: 0000-0002-7332-0924 + - name: Steve Kench + orcid: 0000-0002-7263-6724 - name: Samuel J. Cooper orcid: 0000-0003-4055-6903 doi: ARXIV_DOI journal: "arXiV preprint" month: 8 - title: "Predicting Microstructural Representativity from a Single Image" + title: "Prediction of Microstructural Representativity from a Single Image" year: 2024 \ No newline at end of file diff --git a/README.md b/README.md index 8d63107..85b4c6e 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,24 @@ -# Representativity - -![Tests](https://github.com/tldr-group/Representativity/actions/workflows/tests.yml/badge.svg) +# ImageRep [Try it out!](https://www.imagerep.io/) -You take a micrograph of a material. You segment it, and measure the phase fractions. How sure are you that the phase fraction of the whole material is close to your measurements? -Here we define 'representativity' as [1] -> A microstructure is $(c, d)$-property representative if the measured value of the microstructural property deviates by no more than $d\%$ from the bulk material property, with at least $c\%$ confidence. For example, if $(c,d)=(95,3)$, and the property is phase-fraction, this means we can be $95\%$ confident that the measured phase-fraction is within $3\%$ of the bulk material phase-fraction. - -We introduce the 'ImageRep' model for performing fast phase-fraction representativity estimation from a single microstructural image. This is achieved by estimating the Two-Point Correlation (TPC) function of the image via the FFT. From the TPC the 'Integral Range' can be directly determined - the Integral Range has previously been determined using (slow) statistical methods. We then represent the image as binary squares of length 'Integral Range' which are samples from a Bernoulli distribution with a probability determined by the measured phase fraction. From this we can establish the uncertainty in the phase fraction in the image to a given confidence, **and** the image size that would be needed to meet a given target uncertainty. +Here we introduce the 'ImageRep' method for fast phase fraction representativity estimation from a single microstructural image. This is achieved by calculating the Two-Point Correlation (TPC) function of the image, combined with a data-driven analysis of the [MicroLib](https://microlib.io/) dataset. By applying a statistical framework that utilizes both data sources, we can establish the uncertainty in the phase fraction in the image with a given confidence, **and** the image size that would be needed to meet a given target uncertainty. Further details are provided in our [paper](CITATION.cff). -If you use this model in your research, [please cite us](CITATION.cff). +If you use this ImageRep in your research, [please cite us](CITATION.cff). ## Usage: -This model can be used as python package - see [`example.ipynb`](example.ipynb) or via the [website (imagerep.io)](https://www.imagerep.io/). +This method can be used via the [website (imagerep.io)](https://www.imagerep.io/) or as python package - see [`example.ipynb`](example.ipynb).

-NB: the website may run out of memory for large volumes (>1000x1000x1000) - if this happens run the model locally or contact us +NB: the website may run out of memory for large volumes (>1000x1000x1000) - if this happens run the method locally or contact us ## Limitations: - **This is not the only source of uncertainty!** Other sources *i.e,* segmentation uncertainty, also contribute and may be larger -- For multi-phase materials, this model estimates the uncertainty in phase-fraction of a single (chosen) phase, counting all the others as a single phase (*i.e,* a binary microstructure) +- For multi-phase materials, this method estimates the uncertainty in phase-fraction of a single (chosen) phase, counting all the others as a single phase (*i.e,* a binary microstructure) - Not validated for for images smaller than 200x200 or 200x200x200 - Not validated for large integral ranges/features sizes (>70 px) - Not designed for periodic structures @@ -32,7 +26,7 @@ NB: the website may run out of memory for large volumes (>1000x1000x1000) - if t ## Local Installation Instructions -These instructions are for installing and running the model locally. They assume a UNIX enviroment (mac or linux), but adapting for Windows is straightforward. Note you will need 2 terminals, one for the frontend local server and one for the backend local server. +These instructions are for installing and running the method locally. They assume a UNIX enviroment (mac or linux), but adapting for Windows is straightforward. Note you will need 2 terminals, one for the frontend local server and one for the backend local server. ### Preliminaries @@ -51,7 +45,7 @@ git clone https://github.com/tldr-group/Representativity && cd Representativity pip install -e . ``` -**NOTE: this is all you need to do if you wish to use the model via the python package.** To run the website locally, follow the rest of the instructions. +**NOTE: this is all you need to do if you wish to use the method via the python package.** To run the website locally, follow the rest of the instructions. 2. With your virtual environment activated, and inside the `representativity/` directory, run @@ -86,6 +80,8 @@ yarn && yarn start ## Testing Instructions +![Tests](https://github.com/tldr-group/Representativity/actions/workflows/tests.yml/badge.svg) + 1. Run (with your virtual enviroment activated!) ``` diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ccc87d5..8a33e22 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -8,13 +8,13 @@ import NormalSlider from "./components/NormalSlider"; import { Menu } from "./components/Menu"; import { ErrorMessage, CLSModal, MoreInfo } from "./components/Popups" -import { loadFromTIFF, loadFromImage } from "./components/imageLogic"; +import { loadFromTIFF, loadFromImage, getPhaseFraction } from "./components/imageLogic"; import "./assets/scss/App.scss"; import 'bootstrap/dist/css/bootstrap.min.css'; -const PATH = "http://127.0.0.1:5000"; -//const PATH = "https://samba-segment.azurewebsites.net"; +//const PATH = "http://127.0.0.1:5000"; +const PATH = "https://samba-segment.azurewebsites.net"; //const PATH = "http://localhost:7071/api"; //const PATH = "https://representative.azurewebsites.net/api" const PF_ENDPOINT = PATH + "/phasefraction" @@ -147,7 +147,13 @@ const App = () => { }) const vals = imageInfo?.phaseVals! - const phaseFrac = accurateFractions![vals[selectedPhase - 1]] + const phaseFrac = (accurateFractions != null) ? + accurateFractions[vals[selectedPhase - 1]] + : getPhaseFraction( + imageInfo?.previewData.data!, + vals[selectedPhase - 1] + ); + setPfB([phaseFrac - absErr, phaseFrac + absErr]) if (obj["cls"] > IR_LIMIT_PX) { setShowWarning("cls") } diff --git a/frontend/src/assets/default.tiff b/frontend/src/assets/default_2D.tiff similarity index 100% rename from frontend/src/assets/default.tiff rename to frontend/src/assets/default_2D.tiff diff --git a/frontend/src/assets/default_3D.tiff b/frontend/src/assets/default_3D.tiff new file mode 100644 index 0000000..efb2a2d Binary files /dev/null and b/frontend/src/assets/default_3D.tiff differ diff --git a/frontend/src/components/DragDrop.tsx b/frontend/src/components/DragDrop.tsx index dcaa585..62a6856 100644 --- a/frontend/src/components/DragDrop.tsx +++ b/frontend/src/components/DragDrop.tsx @@ -1,7 +1,8 @@ import React, { useContext, useEffect, useRef, useState } from "react"; import { DragDropProps } from "./interfaces"; -const DEFAULT_IMAGE = "../assets/default.tiff"; +const DEFAULT_IMAGE_2D = "../assets/default_2D.tiff"; +const DEFAULT_IMAGE_3D = "../assets/default_3D.tiff"; export const dragDropStyle = { height: '75vh', width: '75vw', @@ -27,8 +28,8 @@ const DragDrop = ({ loadFromFile }: DragDropProps): JSX.Element => { }; }; - const viewExample = async () => { - const url = new URL(DEFAULT_IMAGE, location.origin); + const viewExample = async (path: string) => { + const url = new URL(path, location.origin); console.log(url) const resp = await fetch(url); const data = await resp.blob(); @@ -43,7 +44,7 @@ const DragDrop = ({ loadFromFile }: DragDropProps): JSX.Element => { onDragOver={handleDrag} onDrop={handeDrop} > - {(!isMobile) && Drag microstructure file or view example!} + {(!isMobile) && Drag microstructure file, or view example viewExample(DEFAULT_IMAGE_2D)}>in 2D or viewExample(DEFAULT_IMAGE_3D)}> 3D} ); } diff --git a/frontend/src/components/Menu.tsx b/frontend/src/components/Menu.tsx index 4d9c64e..e1a2979 100644 --- a/frontend/src/components/Menu.tsx +++ b/frontend/src/components/Menu.tsx @@ -191,12 +191,24 @@ const Result = () => { const lResultRef = useRef(null); const vals = imageInfo?.phaseVals! - const phaseFrac = (accurateFractions != null) ? - accurateFractions[vals[selectedPhase - 1]] - : getPhaseFraction( - imageInfo?.previewData.data!, - vals[selectedPhase - 1] - ); + + const getPhaseFracs = () => { + const accurateAvailable = accurateFractions != null + const coarseAvailable = (imageInfo != null) && (imageInfo.previewData.data != null) + + if (accurateAvailable) { + return accurateFractions[vals[selectedPhase - 1]] + } else if (coarseAvailable) { + return getPhaseFraction( + imageInfo?.previewData.data!, + vals[selectedPhase - 1] + ); + } else { + return 0 + } + } + + const phaseFrac = getPhaseFracs(); const l = analysisInfo?.lForDefaultErr; @@ -257,6 +269,8 @@ const Result = () => { const vol = (ii?.nDims! == 3) ? (ii?.height! * ii?.width! * ii?.width!) : (ii?.height! * ii?.width!) const nMore = (Math.ceil(Math.pow(l!, imageInfo?.nDims!) / vol)) - 1 + const modalTitle = `Results for "${imageInfo?.file?.name}"` + const title = "Phase Fraction Estimation of the Material" const smallResults = ( @@ -313,7 +327,7 @@ const Result = () => { const largeResults = (<> - Results! + {modalTitle} diff --git a/frontend/src/components/Popups.tsx b/frontend/src/components/Popups.tsx index ada3136..43b8cd9 100644 --- a/frontend/src/components/Popups.tsx +++ b/frontend/src/components/Popups.tsx @@ -71,7 +71,7 @@ export const CLSModal = () => { } } - const txt = (showWarning == "over") ? 'Success!' : "Warning!" + const txt = (showWarning == "over") ? 'Good news!' : "Warning!" const bg = (showWarning == "over") ? '#6ac40a' : '#fcba03' return ( @@ -95,12 +95,14 @@ export const MoreInfo = () => { imageInfo: [imageInfo,], analysisInfo: [analysisInfo,], showInfo: [showInfo, setShowInfo], - menuState: [, setMenuState] + menuState: [menuState, setMenuState] } = useContext(AppContext)!; const handleClose = () => { setShowInfo(false); - setMenuState('conf_result'); + if (menuState == "conf_result_full") { + setMenuState('conf_result'); + } }; return ( diff --git a/frontend/src/components/Topbar.tsx b/frontend/src/components/Topbar.tsx index c527f38..5ad9bae 100644 --- a/frontend/src/components/Topbar.tsx +++ b/frontend/src/components/Topbar.tsx @@ -1,4 +1,5 @@ import React, { useContext, useEffect, useRef, useState } from "react"; +import AppContext from "./interfaces"; import Container from 'react-bootstrap/Container'; import Nav from 'react-bootstrap/Nav'; @@ -6,6 +7,10 @@ import Navbar from 'react-bootstrap/Navbar'; import { TopbarProps } from "./interfaces"; const Topbar = ({ loadFromFile, reset, changePhase }: TopbarProps) => { + + const { + showInfo: [showInfo, setShowInfo], + } = useContext(AppContext)!; const fileInputRef = useRef(null); const addData = () => { @@ -24,12 +29,13 @@ const Topbar = ({ loadFromFile, reset, changePhase }: TopbarProps) => { return ( - + {/*path for these assets need to be relative to index.html in assets/*/} - ImageRep + ImageRep