Skip to content

Commit 09762e0

Browse files
author
Max
committed
first commit
0 parents  commit 09762e0

19 files changed

+3785
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist
2+
node_modules

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"typescript.tsdk": "node_modules/typescript/lib"
3+
}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# sandbox-script
2+
3+
## 0.0.1
4+
### Patch Changes
5+
6+
- First published version
7+
- Updated dependencies [undefined]
8+
- @pixinsight/core@0.0.1
9+
- @pixinsight/react@0.0.1
10+
- @pixinsight/ui@0.0.1

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Star De-emphasizer Script for PixInsight
2+
3+
### Introdution
4+
5+
This script uses the method of de-empasizing stars suggested by Adam Block (https://adamblockstudios.com/). The basic idea is that we need to create a so-called "halos" mask in order to fill the space around each star with the data from the starless image.
6+
7+
The recommended way to obtain a starless image is by using Starnet++ process. But there are other ways too.
8+
9+
I highly recommend to watch Adam Block's presentation on his method https://www.youtube.com/watch?v=3DdSDoJfjM4
10+
11+
### Download
12+
13+
### Method
14+
15+
The method consists of the following steps:
16+
17+
1. Get starful image's luminance
18+
2. Apply MultiscaleLinearTransform to it in order to extract structures(stars) of a certain size
19+
3. Apply Binarize process to that
20+
4. Apply MorphologicalTransformation(Dilatio) in order to make binarized stars uniform and round
21+
5. Apply Convolution to smooth dilated stars' edges
22+
6. Substract the luminance image from the convolued image. This way we get a halos mask
23+
7. Apply the starless image to the starful image through the halos mask
24+
8. Enjoy the result or adjust the parameters and retry :)
25+
26+
### Usage
27+
28+
The interface of the script allows you to see how each stage of the process modifies the image.
29+
30+
![Script's Interface](./screenshot.png)
31+
32+
1. Choose the target image and it's corresponding starless image
33+
1. Select a preview area on the main preview image by clicking the mouse and scrolling to zoom in.
34+
1. Press "Process Preview" button
35+
1. You can press the mouse on the "Result" area to compare the result with the original
36+
1. Adjust parameters and press "Process Preview" again to see the changes some of the stages previews and the resulting image
37+
1. When you're ready, press "Apply" button to start the process on the targetimage
38+
1. Close the script
39+
40+
### Suggestions and improvements
41+
42+
If you have any suggestions or feedback on how to improve this script please open an issue in this repository 😉
43+

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "pi-star-de-emphasizer",
3+
"private": "true",
4+
"version": "0.0.1",
5+
"main": "index.js",
6+
"license": "MIT",
7+
"scripts": {
8+
"build": "webpack",
9+
"dev": "webpack --watch"
10+
},
11+
"pixinsight": {
12+
"script": {
13+
"feature-id": "Utilities > Star De-emphasizer",
14+
"feature-info": "Star De-emphasizer script"
15+
}
16+
},
17+
"dependencies": {
18+
"@babel/core": "^7.12.10",
19+
"@babel/preset-env": "^7.12.11",
20+
"@pixinsight/core": "^0.0.1",
21+
"@pixinsight/react": "^0.0.1",
22+
"@pixinsight/ui": "^0.0.1",
23+
"@types/react": "^17.0.0",
24+
"@types/webpack": "^4.41.26",
25+
"@types/webpack-sources": "^2.1.0",
26+
"babel-loader": "^8.2.2",
27+
"react": "^17.0.1",
28+
"ts-loader": "^8.0.14",
29+
"typescript": "^4.1.3",
30+
"webpack": "^5.16.0",
31+
"webpack-cli": "^4.4.0"
32+
}
33+
}

screenshot.png

789 KB
Loading

src/ImagePreview.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {
2+
Align_Center,
3+
FrameStyle_Box,
4+
TextAlign_Center,
5+
} from "@pixinsight/core";
6+
import { UIControl, UIFrame, UILabel, UIVerticalSizer } from "@pixinsight/ui";
7+
import React, { useMemo, useRef, useState } from "react";
8+
9+
export function ImagePreview({
10+
image,
11+
title = "Preview",
12+
children,
13+
...props
14+
}: { image?: Image; title?: string } & React.ComponentProps<typeof UIFrame>) {
15+
const controlRef = useRef<Control>(null);
16+
const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });
17+
18+
const [bmp, offsetX, offsetY] = useMemo(() => {
19+
const ratio = image?.width / image?.height;
20+
const minSize = Math.min(size.w, size.h);
21+
const [sw, sh] =
22+
ratio > 1 ? [minSize, minSize / ratio] : [ratio * minSize, minSize];
23+
24+
const [ew, eh] = [
25+
image?.width / sw > 1
26+
? Math.round(image?.width / sw)
27+
: 1 / Math.round(sw / image?.width),
28+
image?.height / sh > 1
29+
? Math.round(image?.height / sh)
30+
: 1 / Math.round(sh / image?.height),
31+
];
32+
33+
const bmp = image
34+
?.render()
35+
.scaledTo(image?.width / ew, image?.width / ew, 0);
36+
return [bmp, size.w / 2 - bmp?.width / 2, size.h / 2 - bmp?.height / 2];
37+
}, [image, size]);
38+
39+
function onPaint() {
40+
if (!controlRef.current || !bmp) {
41+
return;
42+
}
43+
const control = controlRef.current;
44+
const G = new Graphics(control);
45+
46+
G.drawBitmap(offsetX, offsetY, bmp);
47+
G.end();
48+
49+
gc();
50+
}
51+
52+
function onResize(w: number, h: number) {
53+
setSize({ w, h });
54+
}
55+
56+
return (
57+
<UIVerticalSizer>
58+
<UILabel textAlignment={TextAlign_Center} text={title} />
59+
<UIFrame
60+
frameStyle={FrameStyle_Box}
61+
minWidth={200}
62+
minHeight={200}
63+
{...props}
64+
>
65+
{image ? (
66+
<UIControl ref={controlRef} onPaint={onPaint} onResize={onResize}>
67+
{children}
68+
</UIControl>
69+
) : null
70+
// <UILabel alignment={Align_Center} text={title} />
71+
}
72+
</UIFrame>
73+
</UIVerticalSizer>
74+
);
75+
}

src/ImagePreviewSelect.tsx

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { Align_Center, FrameStyle_Box } from "@pixinsight/core";
2+
import {
3+
UIControl,
4+
UIFrame,
5+
UILabel,
6+
UIPushButton,
7+
UIVerticalSizer,
8+
} from "@pixinsight/ui";
9+
import React, { useEffect, useMemo, useRef, useState } from "react";
10+
11+
export function ImagePreviewSelect({
12+
image,
13+
onRect,
14+
children,
15+
...props
16+
}: { image?: Image; onRect?: (rect: Rect) => void } & React.ComponentProps<
17+
typeof UIFrame
18+
>) {
19+
const controlRef = useRef<Control>(null);
20+
const [zoom, setZoom] = useState(1);
21+
const [isDrag, setIsDrag] = useState(false);
22+
const [scrollAmount, setScrollAmount] = useState(0);
23+
const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });
24+
const [rect, setRect] = useState<Rect>(new Rect());
25+
26+
const [
27+
bmp,
28+
defaultRectSize,
29+
scaleX,
30+
scaleY,
31+
offsetX,
32+
offsetY,
33+
] = useMemo(() => {
34+
const ratio = image?.width / image?.height;
35+
const controlRatio = size.w / size.h;
36+
const [sw, sh] =
37+
controlRatio < 1 ? [size.w, size.w / ratio] : [ratio * size.h, size.h];
38+
const bmp = image?.render().scaledTo(sw, sh);
39+
return [
40+
bmp,
41+
Math.min(image?.width, image?.height),
42+
bmp?.width / image?.width,
43+
bmp?.height / image?.height,
44+
size.w / 2 - bmp?.width / 2,
45+
size.h / 2 - bmp?.height / 2,
46+
];
47+
}, [image, size]);
48+
49+
useEffect(() => {
50+
if (!image) {
51+
return;
52+
}
53+
const newRect = new Rect(defaultRectSize, defaultRectSize);
54+
newRect.moveTo(
55+
(image.width - newRect.width) / 2,
56+
(image.height - newRect.height) / 2
57+
);
58+
setRect(newRect);
59+
setZoom(1);
60+
}, [image]);
61+
62+
useEffect(() => {
63+
if (!image) {
64+
return;
65+
}
66+
const oldCenter = new Point(rect.center);
67+
const newRect = new Rect(rect);
68+
newRect.resizeTo(defaultRectSize / zoom, defaultRectSize / zoom);
69+
newRect.width = Math.round(newRect.width);
70+
newRect.height = Math.round(newRect.height);
71+
newRect.center = oldCenter;
72+
constrainRect(newRect);
73+
setRect(newRect);
74+
}, [zoom]);
75+
76+
useEffect(() => {
77+
if (rect.width !== 0 && rect.height !== 0) {
78+
onRect?.(rect);
79+
}
80+
}, [rect]);
81+
82+
function onPaint() {
83+
if (!controlRef.current || !bmp) {
84+
return;
85+
}
86+
const control = controlRef.current;
87+
const G = new Graphics(control);
88+
89+
G.drawBitmap(offsetX, offsetY, bmp);
90+
G.pen = new Pen(0xff00ff00); //Green
91+
const greenRect = new Rect(
92+
offsetX + rect.x0 * scaleX,
93+
offsetY + rect.y0 * scaleY,
94+
offsetX + rect.x1 * scaleX,
95+
offsetY + rect.y1 * scaleY
96+
);
97+
G.drawRect(greenRect);
98+
G.end();
99+
100+
gc();
101+
}
102+
103+
function onResize(w: number, h: number) {
104+
setSize({ w, h });
105+
}
106+
107+
function onMouseWheel(
108+
x: number,
109+
y: number,
110+
delta: number,
111+
buttonState: number,
112+
modifiers: any
113+
) {
114+
if (Math.abs(scrollAmount) > 50) {
115+
const operand = scrollAmount / Math.abs(scrollAmount);
116+
if (operand > 0) {
117+
setZoom(zoom + 1 > 100 ? 100 : zoom + 1);
118+
} else {
119+
setZoom(zoom - 1 < 1 ? 1 : zoom - 1);
120+
}
121+
setScrollAmount(0);
122+
} else {
123+
setScrollAmount(scrollAmount + delta);
124+
}
125+
}
126+
127+
function constrainRect(rect: Rect) {
128+
const [w, h] = [rect.width, rect.height];
129+
if (rect.left < 0) {
130+
rect.left = 0;
131+
}
132+
if (rect.right > image?.width) {
133+
rect.left = image?.width - rect.width;
134+
}
135+
if (rect.top < 0) {
136+
rect.top = 0;
137+
}
138+
if (rect.bottom > image?.height) {
139+
rect.top = image?.height - rect.height;
140+
}
141+
rect.width = w;
142+
rect.height = h;
143+
}
144+
145+
function updateRectPosition(x: number, y: number) {
146+
const newRect = new Rect(rect);
147+
newRect.center = new Point((x - offsetX) / scaleX, (y - offsetY) / scaleY);
148+
constrainRect(newRect);
149+
newRect.width = Math.round(newRect.width);
150+
newRect.height = Math.round(newRect.height);
151+
setRect(newRect);
152+
}
153+
154+
function onMousePress(x: number, y: number) {
155+
updateRectPosition(x, y);
156+
setIsDrag(true);
157+
}
158+
159+
function onMouseRelease() {
160+
setIsDrag(false);
161+
}
162+
163+
function onMouseMove(x: number, y: number) {
164+
updateRectPosition(x, y);
165+
}
166+
167+
return (
168+
<UIFrame
169+
frameStyle={FrameStyle_Box}
170+
minWidth={300}
171+
minHeight={300}
172+
{...props}
173+
>
174+
<UIVerticalSizer>
175+
{image ? (
176+
<UIControl
177+
ref={controlRef}
178+
onPaint={onPaint}
179+
onMouseWheel={onMouseWheel}
180+
onMousePress={onMousePress}
181+
onMouseRelease={onMouseRelease}
182+
onMouseMove={onMouseMove}
183+
onResize={onResize}
184+
>
185+
{children}
186+
</UIControl>
187+
) : (
188+
<UILabel alignment={Align_Center} text="Preview" />
189+
)}
190+
</UIVerticalSizer>
191+
</UIFrame>
192+
);
193+
}

0 commit comments

Comments
 (0)