Objective: To save image in bi-level format as demonstrated at https://memorynotfound.com/convert-image-black-white-java/
Code:
using Images, ImageView;
function save_as_binary_image(img_path::String, threshold::Float16)
img_binary = load(img_path);
img_binary = (Gray.(img_binary) .> threshold);
imshow(img_binary);
typeof(img_binary);#=>BitArray{2}
save("/path/to/dest/image.png", img_binary);
img_saved = load("/path/to/dest/image.png");
imshow(img_saved);
typeof(img_saved);#=>Array{Gray{Normed{UInt8,8}},2}
end
save_as_binary_image("/path/to/image/file", convert(Float16, 0.5));
It saves as image of depth 8 but not of depth 1.
Please guide me in saving bi-level image to file!
I'm not an Images.jl user yet (soon perhaps) but here's something that works:
using Images, ImageView
function save_binary_image(img_path, threshold)
img_binary = load(img_path)
#info size(img_binary)
tib = Gray.(Gray.(img_binary) .> threshold)
save("$(img_path)-$(threshold).png", tib)
end
save_binary_image("/tmp/mandrill.png", 0.1)
Perhaps you can slowly modify this to do what you want...
It can be useful to work at the REPL, so that you can see the errors immediately.
Related
I want iterate over a list of string, output the string as plain text in jupyter lab then interactively highlight a substring to get easily the start index of the substring and the length. The goal is to do a quick annotation of text and get the coordinates of the substring.
Is it easy or even possible to do something like this with jupyter notebook (lab)? If then How?
I had a look at ipywidgets but couldn't find something for this use case.
Here's an example with the RangeSlider:
import ipywidgets
input_string = 'averylongstring'
widg = ipywidgets.IntRangeSlider(
value = [0, len(input_string)],
min=0, max=len(input_string)
)
output_widg = ipywidgets.Text()
display(widg)
display(output_widg)
def chomp_string(widg):
start,end = tuple(widg['new'])
output_widg.value = input_string[start: end]
widg.observe(chomp_string, names='value')
You can implement this using jp_proxy_widgets. See the following screenshot:
Note that there are warnings about compatibility for selection protocols -- I only tested this on Chrome on a Mac. Also I don't know why the indices are off by one
(select_callback(startOffset+1, endOffset+1);)
Please see https://github.com/AaronWatters/jp_proxy_widget for more information
Edit: Here is the pastable text as requested:
import jp_proxy_widget
select_widget = jp_proxy_widget.JSProxyWidget()
txt = """
Never gonna give you up.
Never gonna let you down.
Never gonna run around and
desert you.
"""
selected_text = None
def select_callback(startOffset, endOffset):
global selected_text
selected_text = txt[startOffset: endOffset]
print ("Selected", startOffset, endOffset, repr(selected_text))
select_widget.js_init("""
// (Javascript) Add a text area.
element.empty()
$("<h3>please select text:</h3>").appendTo(element);
var textarea = $('<textarea cols="50" rows="5">' + txt + "</textarea>").appendTo(element);
// Attach a select handler that calls back to select_callback.
var select_handler = function(event) {;
var target = event.target;
var startOffset = target.selectionStart;
var endOffset = target.selectionEnd;
select_callback(startOffset+1, endOffset+1);
};
textarea[0].addEventListener('select', select_handler);
""", txt=txt, select_callback=select_callback)
# display the widget
select_widget.debugging_display()
I've recently been working a lot with CFrame mechanics while scripting and I've got kind of stuck on this.
Even after using .lookVector, or even Vector3, the Jetpack model position stays equal to the position of the Torso instead of 5 (* -5) behind the torso.
Here is the code I have so far:
local player = script.Parent
local jetpack = game.ReplicatedStorage.Jetpack
local jetpackClone = jetpack:Clone()
jetpackClone.PrimaryPart = jetpackClone.Core
jetpackClone.Parent = player
jetpackClone:moveTo(player.Torso.Position + player.Torso.CFrame.lookVector * -5)
local weld = Instance.new("Motor6D")
weld.Parent = jetpackClone.Core
weld.Part0 = jetpackClone.Core
weld.Part1 = player.Torso
The way to fix this is quite simple.
Like Ahmad said, moveTo is used for models that doesn't have a primary part. But it is not only that.
One thing that Ahmad forgot is that 'lookVector' is not a CFrame, it is a Vector3 instead.
In this fragment, you did
moveTo(player.Torso.Position + player.Torso.CFrame.lookVector * -5)
That would be fine, if you didn't use a numerical value with Vector3's. To fix this, instead, your code should be
local player = script.Parent
local jetpack = game.ReplicatedStorage.Jetpack;
local jetpackClone = jetpack:Clone();
jetpackClone.PrimaryPart = jetpackClone.Core;
jetpackClone.Parent = player; -- Is the 'Player' a Player, or a character??
local weld = Instance.new("Weld", player.Torso) -- We use 'Weld' here, instead of Motor6D
weld.Part1 = jetpackClone.Core;
weld.Part0 = player.Torso;
weld.C0 = CFrame.new(0, 0, -5); -- We use the C0 property of Weld's
That should do it for welding the jetpack to your torso. Though, I would check if the CFrame is correct in it, I am not sure if it is or not, but if the jetpack appears in front of your torso, then replace weld.C0 = CFrame.new(0, 0, -5) to weld.C0 = CFrame.new(0, 0, 5).
Hope my answer helps!
moveTo is used for models that doesn't have a primary part. Which can be inaccurate. Instead use :SetPrimaryPartCFrame() also u were adding Position+CFrame(it would cause an error did u check output?)
To output a single frame from ffmpeg I can do:
ffmpeg -i input.flv -ss 00:00:14.435 -vframes 1 out.png
And to output an image every second, I can do:
ffmpeg -i input.flv -vf fps=1 out%d.png
Would there be a way to create a thumbnail sprite from these outputs to help with the creation of a vtt file for thumbs on seek position?
Here is an example to create jpeg files (280x180) from mp4 video, using ffmpeg, and then assembling this thumbnails into a sprite (png format) using PHP gd2 + writing a VTT file for the video player.
First create 1 image per second with ffmpeg:
ffmpeg -i sprite/MyVideoFile.mp4 -r 1 -s 280x180 -f image2 sprite/thumbs/thumb-%%d.jpg
Then create sprite file + vtt file (example with PHP):
$dirToScan = 'thumbs/';
$filePrefix = 'thumb-';
$fileSuffix = '.jpg';
$thumbWidth = 280;
$thumbHeight = 180;
$imageFiles = array();
$spriteFile = 'sprite.png';
$imageLine = 20;
$vttFile = 'sprite.vtt';
$dst_x = 0;
$dst_y = 0;
# read the directory with thumbnails, file name in array
foreach (glob($dirToScan.$filePrefix.'*'.$fileSuffix) as $filename) {
array_push($imageFiles,$filename);
}
natsort($imageFiles);
#calculate dimension for the sprite
$spriteWidth = $thumbWidth*$imageLine;
$spriteHeight = $thumbHeight*(floor(count($imageFiles)/$imageLine)+1);
# create png file for sprite
$png = imagecreatetruecolor($spriteWidth,$spriteHeight);
# open vtt file
$handle = fopen($vttFile,'wb+');
fwrite($handle,'WEBVTT'."\n");
# insert thumbs in sprite and write the vtt file
foreach($imageFiles AS $file) {
$counter = str_replace($filePrefix,'',str_replace($fileSuffix,'',str_replace($dirToScan,'',$file)));
$imageSrc = imagecreatefromjpeg($file);
imagecopyresized ($png, $imageSrc, $dst_x , $dst_y , 0, 0, $thumbWidth, $thumbHeight, $thumbWidth,$thumbHeight);
$varTCstart = gmdate("H:i:s", $counter-1).'.000';
$varTCend = gmdate("H:i:s", $counter).'.000';
$varSprite = $spriteFile.'#xywh='.$dst_x.','.$dst_y.','.$thumbWidth.','.$thumbHeight;
fwrite($handle,$counter."\n".$varTCstart.' --> '.$varTCend."\n".$varSprite."\n\n");
create new line after 20 images
if ($counter % $imageLine == 0) {
$dst_x=0;
$dst_y+=$thumbHeight;
}
else {
$dst_x+=$thumbWidth;
}
}
imagepng($png,$spriteFile);
fclose($handle);
VTT file looks like:
WEBVTT
1
00:00:00.000 --> 00:00:01.000
sprite.png#xywh=0,0,280,180
2
00:00:01.000 --> 00:00:02.000
sprite.png#xywh=280,0,280,180
3
00:00:02.000 --> 00:00:03.000
sprite.png#xywh=560,0,280,180
...
I am not completely sure what you need/mean with sprite for a vtt file, but there is a nice tool that allows you to combine single images into a big overview picture:
ImageMagick comes with a handy tool called montage
montage - create a composite image by combining several separate images. The images are tiled on the composite image optionally adorned with a border, frame, image name, and more.
You can put the thumbnails together on one or more images with the following command:
montage *.png -tile 4x4 overview.png
It will automatically generate the number of needed pictures to give you an overview.
A little improvement proposal to the answer given by MR_1204: if the final sprite is a PNG, I would avoid the quality decrease caused by JPG compression and rather save the temporary thumbnails as PNGs:
ffmpeg -i sprite/MyVideoFile.mp4 -r 1 -s 280x180 -f image2 sprite/thumbs/thumb-%%d.png
Also, saving to PNG is usually a (tiny) little bit faster than saving to JPG.
Instead, to keep the download small, it might make sense to save (only) the final sprite image as JPG, which in case of PHP and GD only requires to replace imagepng(...) with imagejpeg(...).
Python solution of MR_1204's solution
import ffmpeg
import logging
from pathlib import Path
from config import temp
import os
from PIL import Image
from datetime import datetime, timedelta
import math
logger = logging.getLogger(__name__)
class ScreenshotExtractor:
def __init__(self):
self.screenshot_folder = f"{temp}ss"
self.gap = 10
self.size = "177x100"
self.col = 5
self.ss_width = 177
self.ss_height = 100
def create_sprite_sheet(self, name):
path, dirs, files = next(os.walk(self.screenshot_folder))
file_count = len(files)
img_width = self.ss_width * self.col
img_height = self.ss_height * math.ceil(file_count/self.col)
file_name = f"{name}.jpg"
out_image = Image.new('RGB', (img_width, img_height))
webvtt = "WEBVTT\n\n"
for count, img_file in enumerate(files):
img = Image.open(f"{self.screenshot_folder}/{img_file}")
st_time = timedelta(seconds=count * self.gap)
end_time = timedelta(seconds=(count + 1) * self.gap)
# Adding img to out_file
x_mod = int(count / self.col)
x = 0 + (count - (self.col * x_mod)) * self.ss_width
y = 0 + x_mod * self.ss_height
out_image.paste(img, (x, y))
sprite = f"{file_name}#xywh={x},{y},{self.ss_width},{self.ss_height}"
webvtt += f"{count + 1}\n0{str(st_time)}.000 --> 0{str(end_time)}.000\n{sprite}\n\n"
out_image.save(f"{temp}{file_name}", quality=90)
f = open(f"{temp}{name}.vtt", "w")
f.write(webvtt)
f.close()
return True
def extract_screenshots(self, file_uri, name):
try:
Path(self.screenshot_folder).mkdir(parents=True, exist_ok=True)
vod = ffmpeg.input(file_uri)
vod.output(f"{self.screenshot_folder}/{name}_%04d.png", r=1/self.gap, s=self.size).run()
return True
except Exception as e:
logger.warning(e)
return False
def run(self, file_uri, name):
# TODO - Actually do logic here
self.extract_screenshots(file_uri, name)
self.create_sprite_sheet(name)
Hope this helps somebody
I'm using MATLAB to montage several high-resolution images together, register the overlay coordinates into a text file, then reading the text file and loading the montaged image. However, once I have the montage, the individual images making up the montage lose resolution. Is there a way to to display the montage with the full resolution of each individual image still intact?
Here is the code.
file = 'ImageFile.txt';
info = importdata(file);
ImageNames = info.textdata(:,1);
xoffset = info.data(:,1);
yoffset = info.data(:,2);
for i=1:length(ImageNames)
diffx(i) = xoffset(length(ImageNames),1) - xoffset(i,1);
end
diffx = (diffx)';
for j=1:length(ImageNames)
diffy(j) = yoffset(length(ImageNames),1) - yoffset(j,1);
end
diffy = (diffy)';
colormap(gray(256));
for k=1:length(ImageNames)
imshow(ImageNames{k,1}, 'XData', [diffx(k,1) (size(ImageNames{1},2) + diffx(k,1))], 'YData',[diffy(k,1) (size(ImageNames{1}, 1) + diffy(k,1))]), hold on
end
This is the method that I used to implement montage. You might not feel the same.
I would assume that you have the co-ordinates of every image location in final montage.
Say I have to create a montage of 9 images and they are named as 1.jpg, 2.jpg, 3.jpg,... 9.jpg.
for i=1:9
filename = sprintf('%d.jpg',i);
a{i} = imread(filename);
end
montage = [a{1} a{2} a{3}; a{4} a{5} a{6}; a{7} a{8} a{9}];
imshow(montage);
imwrite(montage, 'montage.jpg');
Or putting it more accurately, I want to be able to get the distance between the top of a control to the top of one of its children (and adding the height member of all the above children yields specious results!) but the process of getting the absolute coordinates, and comparing them, looks really messed up.
I use this function to calculate the height between the tops of 2 tags:
private static function GetRemainingHeight(oParent:Container, oChild:Container,
yParent:Number, yChild:Number):Number {
const ptParent:Point = oParent.localToGlobal(new Point(0, yParent));
const ptChild:Point = oChild.localToGlobal(new Point(0, yChild));
const nHeightOfEverythingAbove:Number = ptChild.y - ptParent.y;
trace(ptChild.y.toString() + '[' + yChild.toString() + '] - ' +
ptParent.y.toString() + '[' + yParent.toString() + '] = ' + nHeightOfEverythingAbove.toString() + ' > ' + oParent.height.toString());
return nHeightOfEverythingAbove;
}
Note that oParent.y == yParent and oChild.y == yChild but I did it this way for binding reasons.
The result I get is very surprising:
822[329] - 124[0] = 698 > 439
which is impossible, because the top of oChild does not disappear below oParent. The only figure I find unexpected is ptChild.y. All the other numbers look quite sane. So I'm assuming that my mistake was in subtracting two figures that are not supposed to be comparable.
Of course, if anyone has a method of calculating the difference between two points that doesn't involve localToGlobal(), that'd be fine, too.
I'm using the 3.5 SDK.
I found a partial answer by looking to http://rjria.blogspot.ca/2008/05/localtoglobal-vs-contenttoglobal-in.html (including the comments). It dithers on whether or not I should be using localToGlobal() or contentToGlobal(), but it filled in some blanks that Adobe's documentation left, which is that you get the global coordinates by feeding the function new Point(0, 0). In the end, I used this:
public static function GetRemainingHeight(oParent:DisplayObject, oChild:DisplayObject,
yParent:Number, yChild:Number):Number {
const ptParent:Point = oParent.localToGlobal(new Point(0, 0));
const ptChild:Point = oChild.localToGlobal(new Point(0, 0));
const nHeightOfEverythingAbove:Number = ptChild.y - ptParent.y;
return nHeightOfEverythingAbove;
}
See question for an explanation for the seemingly unnecessary parameters, which now seem like they might really be irrelevant.
However, I didn't need this function as often as I thought, and I'm not terribly happy w/the way it works anyway. I've learned that the way I've done it, it isn't possible to just make all those parameters to the function Bindable and expect this function to be called when changes to oChild are made. In one case I had to call this function in the handler for the updateComplete event.