Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Max committed Jan 31, 2021
0 parents commit 09762e0
Show file tree
Hide file tree
Showing 19 changed files with 3,785 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
node_modules
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# sandbox-script

## 0.0.1
### Patch Changes

- First published version
- Updated dependencies [undefined]
- @pixinsight/core@0.0.1
- @pixinsight/react@0.0.1
- @pixinsight/ui@0.0.1
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Star De-emphasizer Script for PixInsight

### Introdution

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.

The recommended way to obtain a starless image is by using Starnet++ process. But there are other ways too.

I highly recommend to watch Adam Block's presentation on his method https://www.youtube.com/watch?v=3DdSDoJfjM4

### Download

### Method

The method consists of the following steps:

1. Get starful image's luminance
2. Apply MultiscaleLinearTransform to it in order to extract structures(stars) of a certain size
3. Apply Binarize process to that
4. Apply MorphologicalTransformation(Dilatio) in order to make binarized stars uniform and round
5. Apply Convolution to smooth dilated stars' edges
6. Substract the luminance image from the convolued image. This way we get a halos mask
7. Apply the starless image to the starful image through the halos mask
8. Enjoy the result or adjust the parameters and retry :)

### Usage

The interface of the script allows you to see how each stage of the process modifies the image.

![Script's Interface](./screenshot.png)

1. Choose the target image and it's corresponding starless image
1. Select a preview area on the main preview image by clicking the mouse and scrolling to zoom in.
1. Press "Process Preview" button
1. You can press the mouse on the "Result" area to compare the result with the original
1. Adjust parameters and press "Process Preview" again to see the changes some of the stages previews and the resulting image
1. When you're ready, press "Apply" button to start the process on the targetimage
1. Close the script

### Suggestions and improvements

If you have any suggestions or feedback on how to improve this script please open an issue in this repository 😉

33 changes: 33 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "pi-star-de-emphasizer",
"private": "true",
"version": "0.0.1",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack",
"dev": "webpack --watch"
},
"pixinsight": {
"script": {
"feature-id": "Utilities > Star De-emphasizer",
"feature-info": "Star De-emphasizer script"
}
},
"dependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@pixinsight/core": "^0.0.1",
"@pixinsight/react": "^0.0.1",
"@pixinsight/ui": "^0.0.1",
"@types/react": "^17.0.0",
"@types/webpack": "^4.41.26",
"@types/webpack-sources": "^2.1.0",
"babel-loader": "^8.2.2",
"react": "^17.0.1",
"ts-loader": "^8.0.14",
"typescript": "^4.1.3",
"webpack": "^5.16.0",
"webpack-cli": "^4.4.0"
}
}
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 75 additions & 0 deletions src/ImagePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
Align_Center,
FrameStyle_Box,
TextAlign_Center,
} from "@pixinsight/core";
import { UIControl, UIFrame, UILabel, UIVerticalSizer } from "@pixinsight/ui";
import React, { useMemo, useRef, useState } from "react";

export function ImagePreview({
image,
title = "Preview",
children,
...props
}: { image?: Image; title?: string } & React.ComponentProps<typeof UIFrame>) {
const controlRef = useRef<Control>(null);
const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });

const [bmp, offsetX, offsetY] = useMemo(() => {
const ratio = image?.width / image?.height;
const minSize = Math.min(size.w, size.h);
const [sw, sh] =
ratio > 1 ? [minSize, minSize / ratio] : [ratio * minSize, minSize];

const [ew, eh] = [
image?.width / sw > 1
? Math.round(image?.width / sw)
: 1 / Math.round(sw / image?.width),
image?.height / sh > 1
? Math.round(image?.height / sh)
: 1 / Math.round(sh / image?.height),
];

const bmp = image
?.render()
.scaledTo(image?.width / ew, image?.width / ew, 0);
return [bmp, size.w / 2 - bmp?.width / 2, size.h / 2 - bmp?.height / 2];
}, [image, size]);

function onPaint() {
if (!controlRef.current || !bmp) {
return;
}
const control = controlRef.current;
const G = new Graphics(control);

G.drawBitmap(offsetX, offsetY, bmp);
G.end();

gc();
}

function onResize(w: number, h: number) {
setSize({ w, h });
}

return (
<UIVerticalSizer>
<UILabel textAlignment={TextAlign_Center} text={title} />
<UIFrame
frameStyle={FrameStyle_Box}
minWidth={200}
minHeight={200}
{...props}
>
{image ? (
<UIControl ref={controlRef} onPaint={onPaint} onResize={onResize}>
{children}
</UIControl>
) : null
// <UILabel alignment={Align_Center} text={title} />
}
</UIFrame>
</UIVerticalSizer>
);
}
193 changes: 193 additions & 0 deletions src/ImagePreviewSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { Align_Center, FrameStyle_Box } from "@pixinsight/core";
import {
UIControl,
UIFrame,
UILabel,
UIPushButton,
UIVerticalSizer,
} from "@pixinsight/ui";
import React, { useEffect, useMemo, useRef, useState } from "react";

export function ImagePreviewSelect({
image,
onRect,
children,
...props
}: { image?: Image; onRect?: (rect: Rect) => void } & React.ComponentProps<
typeof UIFrame
>) {
const controlRef = useRef<Control>(null);
const [zoom, setZoom] = useState(1);
const [isDrag, setIsDrag] = useState(false);
const [scrollAmount, setScrollAmount] = useState(0);
const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });
const [rect, setRect] = useState<Rect>(new Rect());

const [
bmp,
defaultRectSize,
scaleX,
scaleY,
offsetX,
offsetY,
] = useMemo(() => {
const ratio = image?.width / image?.height;
const controlRatio = size.w / size.h;
const [sw, sh] =
controlRatio < 1 ? [size.w, size.w / ratio] : [ratio * size.h, size.h];
const bmp = image?.render().scaledTo(sw, sh);
return [
bmp,
Math.min(image?.width, image?.height),
bmp?.width / image?.width,
bmp?.height / image?.height,
size.w / 2 - bmp?.width / 2,
size.h / 2 - bmp?.height / 2,
];
}, [image, size]);

useEffect(() => {
if (!image) {
return;
}
const newRect = new Rect(defaultRectSize, defaultRectSize);
newRect.moveTo(
(image.width - newRect.width) / 2,
(image.height - newRect.height) / 2
);
setRect(newRect);
setZoom(1);
}, [image]);

useEffect(() => {
if (!image) {
return;
}
const oldCenter = new Point(rect.center);
const newRect = new Rect(rect);
newRect.resizeTo(defaultRectSize / zoom, defaultRectSize / zoom);
newRect.width = Math.round(newRect.width);
newRect.height = Math.round(newRect.height);
newRect.center = oldCenter;
constrainRect(newRect);
setRect(newRect);
}, [zoom]);

useEffect(() => {
if (rect.width !== 0 && rect.height !== 0) {
onRect?.(rect);
}
}, [rect]);

function onPaint() {
if (!controlRef.current || !bmp) {
return;
}
const control = controlRef.current;
const G = new Graphics(control);

G.drawBitmap(offsetX, offsetY, bmp);
G.pen = new Pen(0xff00ff00); //Green
const greenRect = new Rect(
offsetX + rect.x0 * scaleX,
offsetY + rect.y0 * scaleY,
offsetX + rect.x1 * scaleX,
offsetY + rect.y1 * scaleY
);
G.drawRect(greenRect);
G.end();

gc();
}

function onResize(w: number, h: number) {
setSize({ w, h });
}

function onMouseWheel(
x: number,
y: number,
delta: number,
buttonState: number,
modifiers: any
) {
if (Math.abs(scrollAmount) > 50) {
const operand = scrollAmount / Math.abs(scrollAmount);
if (operand > 0) {
setZoom(zoom + 1 > 100 ? 100 : zoom + 1);
} else {
setZoom(zoom - 1 < 1 ? 1 : zoom - 1);
}
setScrollAmount(0);
} else {
setScrollAmount(scrollAmount + delta);
}
}

function constrainRect(rect: Rect) {
const [w, h] = [rect.width, rect.height];
if (rect.left < 0) {
rect.left = 0;
}
if (rect.right > image?.width) {
rect.left = image?.width - rect.width;
}
if (rect.top < 0) {
rect.top = 0;
}
if (rect.bottom > image?.height) {
rect.top = image?.height - rect.height;
}
rect.width = w;
rect.height = h;
}

function updateRectPosition(x: number, y: number) {
const newRect = new Rect(rect);
newRect.center = new Point((x - offsetX) / scaleX, (y - offsetY) / scaleY);
constrainRect(newRect);
newRect.width = Math.round(newRect.width);
newRect.height = Math.round(newRect.height);
setRect(newRect);
}

function onMousePress(x: number, y: number) {
updateRectPosition(x, y);
setIsDrag(true);
}

function onMouseRelease() {
setIsDrag(false);
}

function onMouseMove(x: number, y: number) {
updateRectPosition(x, y);
}

return (
<UIFrame
frameStyle={FrameStyle_Box}
minWidth={300}
minHeight={300}
{...props}
>
<UIVerticalSizer>
{image ? (
<UIControl
ref={controlRef}
onPaint={onPaint}
onMouseWheel={onMouseWheel}
onMousePress={onMousePress}
onMouseRelease={onMouseRelease}
onMouseMove={onMouseMove}
onResize={onResize}
>
{children}
</UIControl>
) : (
<UILabel alignment={Align_Center} text="Preview" />
)}
</UIVerticalSizer>
</UIFrame>
);
}
Loading

0 comments on commit 09762e0

Please sign in to comment.