1"use strict";(globalThis.webpackChunkvrgs_docs_v_3_1=globalThis.webpackChunkvrgs_docs_v_3_1||[]).push([[18532],{56032(e,t,r){r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>h});const n=JSON.parse('{"id":"tutorial/tutorial-fractures/tf030-fractures-from-photographs","title":"Fractures from photographs","description":"Extracting fracture traces automatically from outcrop photographs with the AI, ACO and Phase Congruence detectors, and projecting the result onto the 3D model.","source":"@site/versioned_docs/version-3.4/tutorial/tutorial-fractures/tf030-fractures-from-photographs.md","sourceDirName":"tutorial/tutorial-fractures","slug":"/tutorial/tutorial-fractures/tf030-fractures-from-photographs","permalink":"/docs/tutorial/tutorial-fractures/tf030-fractures-from-photographs","draft":false,"unlisted":false,"editUrl":"https://github.com/vrgeoscience/vrgs_docs_v3/tree/master/versioned_docs/version-3.4/tutorial/tutorial-fractures/tf030-fractures-from-photographs.md","tags":[],"version":"3.4","sidebarPosition":3,"frontMatter":{"sidebar_position":3,"description":"Extracting fracture traces automatically from outcrop photographs with the AI, ACO and Phase Congruence detectors, and projecting the result onto the 3D model.","keywords":["fracture AI","U-Net","ACO","phase congruence","automatic fracture detection","trace extraction"]},"sidebar":"docs","previous":{"title":"Mapping fracture traces","permalink":"/docs/tutorial/tutorial-fractures/tf020-mapping-traces"},"next":{"title":"Orientations and fracture sets","permalink":"/docs/tutorial/tutorial-fractures/tf040-orientations-and-sets"}}');var s=r(74848),i=r(28453);const o={sidebar_position:3,description:"Extracting fracture traces automatically from outcrop photographs with the AI, ACO and Phase Congruence detectors, and projecting the result onto the 3D model.",keywords:["fracture AI","U-Net","ACO","phase congruence","automatic fracture detection","trace extraction"]},a="Fractures from photographs",c={},h=[{value:"What you need",id:"what-you-need",level:2},{value:"The pipeline",id:"the-pipeline",level:2},{value:"1. Detect",id:"1-detect",level:3},{value:"2. Extract 2D traces",id:"2-extract-2d-traces",level:3},{value:"3. Review before you project",id:"3-review-before-you-project",level:3},{value:"4. Map to 3D",id:"4-map-to-3d",level:3},{value:"The thing to understand about the orientations you get",id:"the-thing-to-understand-about-the-orientations-you-get",level:2},{value:"Deriving orientations from traces you already have",id:"deriving-orientations-from-traces-you-already-have",level:2},{value:"See also",id:"see-also",level:2}];function d(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"fractures-from-photographs",children:"Fractures from photographs"})}),"\n",(0,s.jsxs)(t.p,{children:["Mapping traces by hand is accurate and slow. VRGS can also ",(0,s.jsx)(t.strong,{children:"detect them in a\nphotograph"})," and project the result onto the model, which turns an afternoon's\ndigitising into a few minutes of detection plus a clean-up pass."]}),"\n",(0,s.jsxs)(t.p,{children:["This page is the route through that pipeline and the decisions in it. Every\nparameter is documented in the ",(0,s.jsx)(t.a,{href:"/docs/general/fractures-structure/FractureMapping",children:"AI Fracture Mapping\nguide"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"what-you-need",children:"What you need"}),"\n",(0,s.jsxs)(t.p,{children:["A ",(0,s.jsx)(t.strong,{children:"calibrated photograph"})," \u2014 an SfM image with a recovered camera, or a photo\nregistered to the model. The projection step ray-casts each trace vertex through\nthe camera onto the model, so an uncalibrated snapshot cannot be used."]}),"\n",(0,s.jsxs)(t.p,{children:["Open it in the ",(0,s.jsx)(t.strong,{children:"Photograph view"}),". Most of the commands below are on the\nphoto's ",(0,s.jsx)(t.strong,{children:"right-click menu"}),"; the tuning sliders are in the ",(0,s.jsx)(t.strong,{children:"Polyline\nSettings"})," property pane."]}),"\n",(0,s.jsx)(t.h2,{id:"the-pipeline",children:"The pipeline"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{children:" Photograph \u2500\u2500\u25ba detector \u2500\u2500\u25ba probability map \u2500\u2500\u25ba 2D traces \u2500\u2500\u25ba 3D traces \u2500\u2500\u25ba orientations\n"})}),"\n",(0,s.jsx)(t.p,{children:"Only the first step differs between the three detectors. Once a probability map\nexists, everything downstream is identical."}),"\n",(0,s.jsx)(t.h3,{id:"1-detect",children:"1. Detect"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Detector"}),(0,s.jsx)(t.th,{children:"Reach for it when"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Fracture AI"})}),(0,s.jsx)(t.td,{children:"The default. A bundled U-Net (ResNet-34) trained on fracture imagery. Fastest to a usable result, and the right first try on almost any outcrop photo."})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Ant Colony Optimisation (ACO)"})}),(0,s.jsxs)(t.td,{children:["Fractures are discontinuous, low-contrast, or lost in texture \u2014 ACO's swarm follows continuity where a per-pixel classifier gives up. See the ",(0,s.jsx)(t.a,{href:"/docs/general/fractures-structure/aco_image_guide",children:"ACO guide"}),"."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Phase Congruence"})}),(0,s.jsx)(t.td,{children:"A classical, illumination- and contrast-invariant detector. Useful on strongly shadowed faces, and when you want a result that does not depend on what the network was trained on."})]})]})]}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"Fracture AI"})," is the ",(0,s.jsx)(t.strong,{children:"Fracture"})," button on the image-tools ribbon. It produces\na per-pixel probability map, shown as a colour overlay, with the detection\nthreshold set to ",(0,s.jsx)(t.strong,{children:"0.5"}),"."]}),"\n",(0,s.jsx)(t.p,{children:"That threshold is the first thing to tune, and you can see its effect live in\nthe colour-map properties pane:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Lower (0.3\u20130.45)"})," catches faint or thin fractures, at the cost of speckle."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Higher (0.55\u20130.7)"})," keeps only confident detections \u2014 cleaner, but faint\ntraces break into fragments."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"2-extract-2d-traces",children:"2. Extract 2D traces"}),"\n",(0,s.jsxs)(t.p,{children:["Right-click \u2192 ",(0,s.jsx)(t.strong,{children:"Extract Fracture Lines (2D)"}),". The probability map is binarized,\nskeletonised to a one-pixel centre-line, traced as a graph, joined end-to-e
1nd and\nsimplified. The result is an editable orange preview on the image."]}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"Nothing has touched the 3D model yet."})," This is deliberate \u2014 extraction is\ninstant and projection is slow, so you are meant to iterate here."]}),"\n",(0,s.jsx)(t.p,{children:"Two problems dominate, and they pull in opposite directions:"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Symptom"}),(0,s.jsx)(t.th,{children:"Fix"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:"One fracture came out as five fragments"}),(0,s.jsxs)(t.td,{children:["Raise ",(0,s.jsx)(t.strong,{children:"Join max gap"}),"; loosen ",(0,s.jsx)(t.strong,{children:"Join max orientation"})," to 30\u201335\xb0. Keep hysteresis on and lower its band to ~50%."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:"Two separate fractures got bridged into one"}),(0,s.jsxs)(t.td,{children:["Lower ",(0,s.jsx)(t.strong,{children:"Join max gap"}),"; tighten ",(0,s.jsx)(t.strong,{children:"orientation"})," and ",(0,s.jsx)(t.strong,{children:"kink"}),"."]})]})]})]}),"\n",(0,s.jsxs)(t.p,{children:["Joining is non-destructive: change a slider, run ",(0,s.jsx)(t.strong,{children:"Join Fracture Segments"}),"\nagain, and it recomputes from the original fragments. Settle the join settings\n",(0,s.jsx)(t.em,{children:"before"})," doing any manual editing, because re-joining discards manual edits."]}),"\n",(0,s.jsx)(t.h3,{id:"3-review-before-you-project",children:"3. Review before you project"}),"\n",(0,s.jsx)(t.p,{children:"This is the step people skip, and it is the one that decides whether the study\nis any good. The detector will have found things that are not fractures \u2014\nbedding, vegetation edges, shadow lines, the join between two photos."}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Segment Rose Diagram"})," (right-click \u2192 ",(0,s.jsx)(t.em,{children:"Show Segment Rose Diagram"}),") shows a\nlength-weighted rose of trace directions. ",(0,s.jsx)(t.strong,{children:"Drag a wedge"})," to keep only traces\nin one direction band; the length histogram below it drags to drop traces\nshorter than a minimum. Both filters carry through to the 3D projection."]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.strong,{children:"2D line-edit tools"})," on the image-tools ribbon do the rest: erase a\nline, join two, split one, move or insert a vertex."]}),"\n"]}),"\n",(0,s.jsx)(t.admonition,{title:"The rose diagram is a filter, not an analysis",type:"warning",children:(0,s.jsxs)(t.p,{children:["Dragging a wedge is a quick way to isolate one set for projection. It is ",(0,s.jsx)(t.em,{children:"not"}),"\nwhere you decide what the sets are \u2014 this rose is measured in image space on one\nphotograph, so it carries that photo's viewing geometry with it. Set\nidentification belongs on the ",(0,s.jsx)(t.a,{href:"/docs/tutorial/tutorial-fractures/tf040-orientations-and-sets",children:"stereonet"}),",\nafter projection, in real 3D orientations."]})}),"\n",(0,s.jsx)(t.h3,{id:"4-map-to-3d",children:"4. Map to 3D"}),"\n",(0,s.jsxs)(t.p,{children:["Right-click \u2192 ",(0,s.jsx)(t.strong,{children:"Map Fracture Lines to 3D"}),", with a choice of output:"]}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"(Polylines)"})," \u2014 3D trace polylines on the model, in a group named\n",(0,s.jsx)(t.code,{children:"ACO_<photo>"}),". Choose this if you want traces for intensity mapping, or want\nto edit them in 3D before deriving orientations."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"(Orientations)"})," \u2014 the same reprojection, but each trace becomes a single\nvirtual orientation measurement, ready to feed straight into fracture sets and\nthe DFN."]}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:["Traces whose vertices mostly miss the model geometry are dropped. This is the\nslow step \u2014 one ray-cast per vertex \u2014 so raising the ",(0,s.jsx)(t.strong,{children:"Simplification value"}),"\nspeeds it up materially."]}),"\n",(0,s.jsx)(t.h2,{id:"the-thing-to-understand-about-the-orientations-you-get",children:"The thing to understand about the orientations you get"}),"\n",(0,s.jsxs)(t.p,{children:["Every point of a trace lies on the fracture plane, so fitting a plane through\nthe reprojected 3D trace recovers the ",(0,s.jsx)(t.strong,{children:"true"})," fracture orientation \u2014 ",(0,s.jsx)(t.strong,{children:"but only\nwhere the outcrop has relief along that trace"}),". The relief makes the trace bend\nout of a straight line, and that is what pins the plane down."]}),"\n",(0,s.jsxs)(t.p,{children:["On a ",(0,s.jsx)(t.strong,{children:"flat face"})," the trace is a straight line, which cannot define a unique\nplane. VRGS falls back to an ",(0,s.jsx)(t.strong,{children:"apparent"})," dip that assumes the fracture is\nlocally perpendicular to the outcrop."]}),"\n",(0,s.jsxs)(t.p,{children:["VRGS tells you which you got. Each virtual orientation carries a ",(0,s.jsx)(t.strong,{children:"quality"}),"\nscore (0\u20131), is coloured ",(0,s.jsx)(t.strong,{children:"red (low) \u2192 green (high)"}),", and has the score\nappended to its label as ",(0,s.jsx)(t.code,{children:"q=\u2026"}),". The summary reports how many were true versus\napparent."]}),"\n",(0,s.jsx)(t.admonition,{title:"Read the colours before you trust the set statistics",type:"tip",children:(0,s.jsx)(t.p,{children:"A wall of red measurements off a flat quarry face is not a fracture population \u2014\nit is one apparent dip repeated. Either capture the same fractures on a second,\nnon-coplanar face, or weed the low-quality measurements out before fitting set\nstatistics. A Fisher K computed over apparent dips is a confident number about\nnothing."})}),"\n",(0,s.jsx)(t.h2,{id:"deriving-orientations-from-traces-you-already-have",children:"Deriving orientations from traces you already have"}),"\n",(0,s.jsxs)(t.p,{children:["If you mapped traces by hand, or projected them as polylines, you can derive\norientations from them at any point: select the trace group ",(0,s.jsx)(t.strong,{children:"and"})," the outcrop\nmesh in the tree, then ",(0,s.jsx)(t.strong,{children:"Estimate Orientations from Selected Traces"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The same plane-fit and the same quality scoring apply, and near-straight traces\nare rejected outright rather than given a misleading orientation. The results\nland in a group named ",(0,s.jsx)(t.em,{children:'"Virtual orientations from <mesh>"'}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"see-also",children:"See also"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/general/fractures-structure/FractureMapping",children:"AI Fracture Mapping"})," \u2014 every setting, tuning recipes, and the Phase Congruence reference."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/general/fractures-structure/aco_image_guide",children:"Ant Colony Optimisation"})," \u2014 the ACO detector in full."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/general/meshes-point-clouds/sfm-user-guide",children:"Structure from Motion"})," \u2014 building the calibrated photographs in the first place."]}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:["Next: ",(0,s.jsx)(t.a,{href:"/docs/tutorial/tutorial-fractures/tf040-orientations-and-sets",children:"orientations and fracture sets"}),"."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453(e,t,r){r.d(t,{R:()=>o,x:()=>a});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.