- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一组由耦合扫描电子显微镜和能量色散光谱生成的图像和 X 射线数据。这是我的问题:
我像这样对岩石表面的横断面进行了成像(紫色框勾勒出横断面区域):
我想要非常高的分辨率,所以我使用 7 张放大 3000 倍的图像,并在 Photoshop 中使用 photomerge 脚本将它们拼接在一起。以下是单个图像的示例:
及其在光合并图像横断面中的位置:
在这 7 个位置中的每一个,我还收集了 X 射线数据,这些数据为检测到的每个元素生成一个元素图,并将其写入 TIFF。我还想将每个元素图 TIFF 拼接在一起,这样我就可以将它叠加在岩石的合并横断面图像上。这是我想要的结果:
问题是元素映射中没有足够的特征来将它们与 photomerge 拼接在一起。它基本上是二元的——如果检测到一个元素,则像素是某种颜色(如在我的示例图像中,红色代表铁或黄色代表硫),如果未检测到该元素,则为黑色。您可以看到大部分元素贴图大部分是黑色的。
我现在有约 20 个横断面 x 7 个图像,每个 x 约 10 个元素,这导致需要将约 1400 个图像放在一起,因此需要自动化。
我的想法是用 photomerge 将岩石图像拼接在一起。 photomerge 的输出是一个智能对象,其中每个图像都是一个图层。然后,我将使用脚本来获取光合并图像对象中 7 个图像中每一个的左上角坐标、宽度和高度。然后,我会将这些属性放置并分配给 7 个图像的每个相应元素映射,以生成“合并”元素映射以覆盖在图像上。我尝试自己解决这个问题,但我并不精通 javascript,也无法完全理解 Photoshop API。
我在 Github here 上上传了一个示例数据集. 7 个样带位置从左到右依次为:-2、-1、0、1、2、3、4。每个位置都有岩石图像和带有元素数据的子目录。
最佳答案
我不知道 Photoshop 或 R,JavaScript 也是如此:
const names = { // map from directory names to patterns (where "#" stands for position index) of names of images therein
"SEM_images" : "pos# image.tif",
"Al" : "Al Kα1 pos# map data.tif",
"Ba" : "Ba Lα1 pos# map data.tif",
"C" : "C Kα1_2 pos# map data.tif",
"Ca" : "Ca Kα1 pos# map data.tif",
"Fe" : "Fe Kα1 pos# map data.tif",
"Hg" : "Hg Lα1 pos# map data.tif",
"Ir" : "Ir Lα1 pos# map data.tif",
"K" : "K Kα1 pos# map data.tif",
"Mg" : "Mg Kα1_2 pos# map data.tif",
"Mn" : "Mn Kα1 pos# map data.tif",
"Na" : "Na Kα1_2 pos# map data.tif",
"O" : "O Kα1 pos# map data.tif",
"Os" : "Os Lα1 pos# map data.tif",
"P" : "P Kα1 pos# map data.tif",
"S" : "S Kα1 pos# map data.tif",
"Si" : "Si Kα1 pos# map data.tif",
"Ti" : "Ti Kα1 pos# map data.tif"
}
const SCALE = 1/10 // scale of output images
const OVERLAP = 1.0 // minimum *tested* (horizontal) overlap of images relative to their width
const H_BOX = 0.1 // height of comparison box relative to height of images
const W_BOX = 0.1 // width of comparison box relative to width of images
const ADJUSTMENT = 0 // (vertical) adjustment of comparison box [pixels]
/* Merge images given:
* dataset - dataset address as String
* directory - directory name for images as String
* pattern - pattern (where "#" stands for position index) of names of images in directory
* pos_min - minimum position index of images as Number
* pos_max - maximum position index of images as Number
*/
function Merge(dataset, directory, pos_min, pos_max) {
if (dataset[dataset.length - 1] != "/") dataset += "/"
const images = []
for (let pos = pos_min; pos <= pos_max; ++pos) (images[pos - pos_min] = new Image).src = dataset + directory + "/" + names[directory].replace("#", pos)
merge(images, dataset, pos_min, pos_max)
}
function Laplacian(imagedata) { // 5-point stencil approximation
const data = imagedata.data
const L = data.length/4
const grayscale = new Float32Array(L)
for (let i = 0; i < L; ++i) {
const I = 4*i
grayscale[i] = (data[I ] + data[I + 1] + data[I + 2])/3
}
const Laplacian = new Float32Array(L)
//const H = imagedata.height
const Hm1 = imagedata.height - 1
const W = imagedata.width
const Wm1 = W - 1
for (let r = 1; r < Hm1; ++r) {
const R = r*W
for (let c = 1; c < Wm1; ++c) {
const i = R + c
Laplacian[i] = grayscale[i - W] + grayscale[i + W] + grayscale[i - 1] + grayscale[i + 1] - 4*grayscale[i]
}
}
for (let c = 1; c < Wm1; ++c) {
//const i = c
Laplacian[c] = grayscale[c + W] + grayscale[c - 1] + grayscale[c + 1] - 4*grayscale[c]
}
for (let c = 1; c < Wm1; ++c) {
const i = Hm1*W + c
Laplacian[i] = grayscale[i - W] + grayscale[i - 1] + grayscale[i + 1] - 4*grayscale[i]
}
for (let r = 1; r < Hm1; ++r) {
const i = r*W
Laplacian[i] = grayscale[i - W] + grayscale[i + W] + grayscale[i + 1] - 4*grayscale[i]
}
for (let r = 1; r < Hm1; ++r) {
const i = r*W + Wm1
Laplacian[i] = grayscale[i - W] + grayscale[i + W] + grayscale[i - 1] - 4*grayscale[i]
}
{
const Lm1 = L - 1
const LmW = L - W
Laplacian[0 ] = grayscale[W ] + grayscale[1 ] - 4*grayscale[0 ]
Laplacian[W ] = grayscale[2*W ] + grayscale[Wm1 ] - 4*grayscale[W ]
Laplacian[LmW] = grayscale[LmW - W] + grayscale[LmW + 1] - 4*grayscale[LmW]
Laplacian[Lm1] = grayscale[Lm1 - W] + grayscale[Lm1 - 1] - 4*grayscale[Lm1]
}
return Laplacian
}
function merge(images, dataset, pos_min, pos_max) {
for (const image of images) if (!image.complete) {
setTimeout(merge, 1000, images, dataset, pos_min, pos_max) // wait 1000ms = 1s
return
}
let Row, Col
const Coords = [[Row = 0, Col = 0]]
let index = 0
let image = images[index]
const H = image.naturalHeight
const W = image.naturalWidth
if (W*H == 0) return []
const canvas = document.createElement("canvas")
canvas.height = H
canvas.width = W
const context = canvas.getContext('2d')
context.drawImage(image, 0, 0)
let prev = Laplacian(context.getImageData(0, 0, W, H))
const length = images.length
const h = Math.round(H_BOX*H)
const Hmh = H - h
const w = Math.round(W_BOX*W)
const o = Math.max(Math.round((1 - OVERLAP)*W), w)
const Wmw = W - w
const row_offset = Math.round(Hmh/2) + ADJUSTMENT
const offset = row_offset*W
for (++index; index < length; ++index) {
image = images[index]
if (image.naturalHeight != H || image.naturalWidth != W) alert("Dimension mismatch: " + image.src)
context.drawImage(image, 0, 0)
const curr = Laplacian(context.getImageData(0, 0, W, H))
let max = -1
let row, col
for (let r = 0; r < Hmh; ++r) {
const R = r*W
for (let c = o; c < Wmw; ++c) {
let m = 0
for (let i = 0; i < h; ++i) {
const I = i*W
const K = R + I + c
const k = offset + I
for (let j = 0; j < w; ++j) if (prev[K + j]*curr[k + j] > 0) ++m
}
if (m > max) {
max = m
row = r
col = c
}
}
}
Coords[index] = [(Row += row - row_offset)/H, (Col += col)/W]
prev = curr
}
Stitch(dataset, pos_min, pos_max, Coords)
}
function Stitch(dataset, pos_min, pos_max, Coords) {
if (dataset[dataset.length - 1] != "/") dataset += "/"
document.body.appendChild(document.createElement("h1")).innerText = `${dataset} :[${pos_min},${pos_max}] @${JSON.stringify(Coords)}`
const tasks = []
for (const directory in names) {
document.body.appendChild(document.createElement("h2")).innerText = directory
const images = []
for (let pos = pos_min; pos <= pos_max; ++pos) (images[pos - pos_min] = new Image).src = dataset + directory + "/" + names[directory].replace("#", pos)
const target = document.body.appendChild(document.createElement("img"))
target.height = 0
target.width = 0
tasks.push([images, target])
}
process(tasks, Coords)
}
const ROW = 0
const COL = 1
function stitch(images, Coords) {
let image
let index
for (index in images) {
image = images[index]
if (image.naturalHeight != 0 && image.naturalWidth != 0) break
}
const H = image.naturalHeight
const W = image.naturalWidth
const canvas = document.createElement("canvas")
let r_min = 0
let r_max = 0
let c_min = 0
let c_max = 0
for (coords of Coords) {
const r = coords[ROW]
const c = coords[COL]
if (r < r_min) r_min = r
if (r > r_max) r_max = r
if (c < c_min) c_min = c
if (c > c_max) c_max = c
}
canvas.height = (r_max - r_min + 1)*H
canvas.width = (c_max - c_min + 1)*W
const context = canvas.getContext('2d')
if (context == null) {
let list = ""
for (const image of images) list += "\n- " + image.src
alert("Too large: stitching area required for:" + list)
return
}
let coords = Coords[index]
let row = (coords[ROW] - r_min)*H
let col = (coords[COL] - c_min)*W
context.drawImage(image, col, row)
const length = images.length
for (++index; index < length; ++index) {
image = images[index]
if (image.naturalHeight == 0 || image.naturalWidth == 0) continue
if (image.naturalHeight != H || image.naturalWidth != W) alert("Dimension mismatch: " + image.src)
coords = Coords[index]
row = coords[ROW]*H
col = coords[COL]*W
context.drawImage(image, col, row)
}
return canvas.toDataURL()
}
function process(tasks, Coords) {
const task = tasks.shift()
const images = task[0]
for (const image of images) if (!image.complete) {
tasks.push(task)
setTimeout(process, 1000, tasks, Coords) // wait 1000ms = 1s
return
}
const target = task[1]
target.src = stitch(images, Coords)
target.onload = function () {
this.height = SCALE*this.naturalHeight
this.width = SCALE*this.naturalWidth
this.style = "border: solid black 1px"
}
if (tasks.length > 0) process(tasks, Coords)
}
要运行,请执行以下操作:
Merge("https://raw.githubusercontent.com/CaitlinCasar/dataStitcher/master/example_dataset/", "SEM_images", -2, 4)
带有 Fe 覆盖的示例 SEM_images:
关于javascript - 在 Photoshop 或 R 中将来自耦合显微镜/光谱学的图像和数据拼接成全景图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60675149/
为大型网站创建所有艺术作品通常涉及几十个 50+mb 的 Photoshop 文件。通常,给定的模块可能出现在多个文件中。 有没有办法从另一个文件引用经常使用的模块? 例如 -“site-sectio
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我是 Photoshop 脚本的新手。 我想将图像图像(从我的硬盘)作为带有定位的新图层加载到事件文档中。如何才能做到这一点?有人可以分享代码吗? 谢谢 最佳答案 您可以打开 Photoshop 文件
在 photoshop 中,假设我有一些文本图层,其内容如下: Text layer 1: 1@@text01@@abc Text layer 2: 2@@text02@@cef Text lay
我在 Photoshop 中有 500 个图标图像,每个对象周围都有不同的空白区域。我想知道是否有任何方法可以通过 photoshop 运行一个 Action 来裁剪每个图像,以便它删除每个图标周围的
我在 Photoshop 中有 6 个组,每个组中包含多个图层。我希望打开/关闭每个组中的图层以创建图像的所有可能组合。 有人能指出我正确的方向吗? 我从来没有在 Photoshop 中编写过脚本,而
我想开始用 Photoshop 做一些脚本,我想知道是否有一个编辑器已经拥有 Photoshop 的对象或允许加载 Photoshop 的 DOM 以进行智能感知。 任何指针? 最佳答案 Adobe
几乎从一开始,Photoshop 文件就以 8BPS 开始。 (我已经在 2.5 版本中验证了这一点)它在某些时候一定具有某种意义。 我认为 8B 可能指的是位/ channel ,但保存为 16 或
如何在Photoshop中使用Javascript获取/设置当前工具? #target photoshop if (app.currentTool == BRUSH_TOOL) { app.c
几乎从一开始,Photoshop 文件就以 8BPS 开始。 (我已经验证回 2.5 版)它一定在某些时候有一些意义。 我认为 8B 可能指的是位/ channel ,但保存为 16 或 32 没有区
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8 年前关闭。 Improve this
我有非常大的 1 位图像,我需要在 Photoshop 中写入文本数组。我可以在 javascript 中通过将图像转换为灰度然后为每个文本 block 创建一个新层来执行此操作,但我希望能够将文本直
如果我有一个具有以下设置的 photoshop 投影 Blend Mode - rgb(0,0,0) / Opacity - 25% / Angle - 135 degrees / Distance
我正在编写一个脚本,它将遍历图层,修剪它们并导出。到目前为止,我拥有完成此脚本所需的大部分元素。我唯一找不到的是如何显示/隐藏单个图层。我找到了显示/隐藏所有图层的功能,但对于单个图层没有任何功能。
如何在不裁剪的情况下查看矩形选取框选定区域的大小?在paint.net中这很容易,但我必须在photoshop cs 5中完成。在选择区域时,我应该能够看到所选区域的尺寸。我怎样才能做到这一点? 此外
在实现单选按钮时遇到问题。我知道 CS2 中的单选按钮可能有问题,但我不确定哪里出错了。我怀疑我的括号或逗号放错地方了;但看不到它。谢谢。 var dlg = "dialog {text:'Scrip
每种文件格式的技术规范/功能是什么? 一种类型是否比另一种更好地处理某些类型的图形? 最佳答案 XCF 支持保存每一层、当前选择、 channel 、透明度、路径和指南。但是,与 Adobe Ph
我希望 Photoshop 为给定的文件夹自动执行以下任务: 加载给定文件夹中的所有 PNG 文件。 将每个文件的模式转换为RGB 颜色 为每个文件添加一层 在同一文件夹中将文件另存为 PSD 有人告
我第一次编写一些 Photoshop 脚本,如果有一个类似 console.log 的函数来在 ExtendScript Toolkit App 的 Javascript 控制台中输出数组和对象值,那
我不知道如何将我为按钮制作的 Photoshop 形状导入 android,而不带背景。即使我将 photoshop 中的背景设置为透明并将其另存为 PNG,当我在 android 中将它用作我的按钮
我是一名优秀的程序员,十分优秀!