I've read frame which is encoded with H264, decoded it, and converted it to YUV420P and the data is stored in frameYUV420->data, (type of frame is AVFrame). I want to save that data into a file that can be displayed with GIMP for example.
I know how to save RGB25 pixel format but i'm not quite sure how to do YUV420P. Though i know that Y component will take width x height , and Cb/Cr will take (width/2) x (height/2) amount of space needed to save the data. So i'm guessing i need to first write Y data, and after that i need to write Cb and Cr data. Does anyone have finished code that i could take a look at?
void SaveAvFrame(AVFrame *avFrame)
{
FILE *fDump = fopen("...", "ab");
uint32_t pitchY = avFrame->linesize[0];
uint32_t pitchU = avFrame->linesize[1];
uint32_t pitchV = avFrame->linesize[2];
uint8_t *avY = avFrame->data[0];
uint8_t *avU = avFrame->data[1];
uint8_t *avV = avFrame->data[2];
for (uint32_t i = 0; i < avFrame->height; i++) {
fwrite(avY, avFrame->width, 1, fDump);
avY += pitchY;
}
for (uint32_t i = 0; i < avFrame->height/2; i++) {
fwrite(avU, avFrame->width/2, 1, fDump);
avU += pitchU;
}
for (uint32_t i = 0; i < avFrame->height/2; i++) {
fwrite(avV, avFrame->width/2, 1, fDump);
avV += pitchV;
}
fclose(fDump);
}
int saveYUVFrameToFile(AVFrame* frame, int width, int height)
{
FILE* fileHandle;
int y, writeError;
char filename[32];
static int frameNumber = 0;
sprintf(filename, "frame%d.yuv", frameNumber);
fileHandle = fopen(filename, "wb");
if (fileHandle == NULL)
{
printf("Unable to open %s...\n", filename);
return ERROR;
}
/*Writing Y plane data to file.*/
for (y = 0; y < height; y++)
{
writeError = fwrite(frame->data[0] + y*frame->linesize[0], 1, width, fileHandle);
if (writeError != width)
{
printf("Unable to write Y plane data!\n");
return ERROR;
}
}
/*Dividing by 2.*/
height >>= 1;
width >>= 1;
/*Writing U plane data to file.*/
for (y = 0; y < height; y++)
{
writeError = fwrite(frame->data[1] + y*frame->linesize[1], 1, width, fileHandle);
if (writeError != width)
{
printf("Unable to write U plane data!\n");
return ERROR;
}
}
/*Writing V plane data to file.*/
for (y = 0; y < height; y++)
{
writeError = fwrite(frame->data[2] + y*frame->linesize[2], 1, width, fileHandle);
if (writeError != width)
{
printf("Unable to write V plane data!\n");
return ERROR;
}
}
fclose(fileHandle);
frameNumber++;
return NO_ERROR;
Basicly this is what i came up with using several examples provided by FFmpeg and stackoverflow users.
Related
I am trying to draw a rectangle around the body using its upper left corner and bottom right corner detected by Kinect.
The left most and the highest points are detected but I have difficulty finding the right most and the lowest point. The current right mark is jumping up and down and does not move in x-direction.
import org.openkinect.processing.*;
Kinect2 kinect2;
float minThresh = 420;
float maxThresh = 1500;
PImage img;
void setup() {
size(512, 424);
kinect2 = new Kinect2(this);
kinect2.initDepth();
kinect2.initDevice();
img = createImage(kinect2.depthWidth, kinect2.depthHeight, RGB);
}
void draw() {
background(0);
img.loadPixels();
PImage dImg = kinect2.getDepthImage();
int[] depth = kinect2.getRawDepth();
// left side
int leftRecord = kinect2.depthWidth;
int lx = 0;
int ly = 0;
// right side
int rightRecord = 0;
int rx =0;
int ry = 0;
for (int x = 0; x < kinect2.depthWidth; x++) {
for (int y = 0; y < kinect2.depthHeight; y++) {
int offset = x + y*kinect2.depthWidth;
// Grabbing the raw depth
int d = depth[offset];
// Testing against threshold
if (d > minThresh && d < maxThresh && x>50) {
img.pixels[offset] = color(255, 0, 150);
//finding the left most point
if (x < leftRecord) {
leftRecord = x;
lx = x;
ly = y;
}
// finding the right most point
// THE BIT THAT DOES NOT WORK
if( x > rightRecord && x < kinect2.depthWidth){
rightRecord = x;
rx = x;
ry = y;
}
} else {
img.pixels[offset] = dImg.pixels[offset];
}
}
}
img.updatePixels();
image(img, 0, 0);
fill(150, 0, 255);
ellipse(lx,ly,30,30);
ellipse(rx,ry,30,30);
}
Here I attach my code that I use to Draw the Histogram of the Contrasted image and also to convert a gray image into Contrast Image. Here I used low pint as 122 and highest point as 244. In the output histogram it reduce the height of the histogram.
I cannot find the error in my code
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
using namespace cv;
using namespace std;
int main(int argc, char* argv[]) {
Mat img = imread(argv[1], 1);
if (!img.data) {
cout << "Could not find the image!" << endl;
return -1;
}
int height = img.rows;
int width = img.cols;
int widthstep = img.step;
int ch = img.channels();
printf("Height : %d\n", height);
printf("Width : %d\n", width);
printf("Widthstep : %d\n", widthstep);
printf("No of channels : %d\n", ch);
Mat gray_image(height, width, CV_8UC1, Scalar(0));
cvtColor(img, gray_image, COLOR_BGR2GRAY);
Mat new_image = gray_image.clone();
int v;
int output{};
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int v = (int)gray_image.at<uchar>(y, x);
if (v >= 0 && v <= 122) {
output = int((6 / 122) * v);
}
else if (v > 100 && v <= 244) {
output = int(((244) / (122)) * (v - 122) + 6);
}
else if (v > 244 && v <= 255) {
output = int(((5) / (11)) * (v - 244) + 250);
}
new_image.at<uchar>(y, x) = (uchar)output;
}
}
int histn[256];
for (int i = 0; i < 256; i++) {
histn[i] = 0;
}
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
histn[(int)new_image.at<uchar>(y, x)] = histn[(int)new_image.at<uchar>(y, x)] + 1;
}
}
for (int i = 0; i < 256; i++) {
cout << i << ":" << histn[i] << endl;
}
int hist_wn = 512;
int hist_hn = 400;
int bin_wn = cvRound((double)hist_wn / 256);
Mat new_histogramImage(hist_hn, hist_wn, CV_8UC1, Scalar(255));
int maxn = histn[0];
for (int i = 0; i < 256; i++) {
if (maxn < histn[i]) {
maxn = histn[i];
}
}
for (int i = 0; i < 256; i++) {
histn[i] = ((double)histn[i] / maxn) * new_histogramImage.rows;
}
for (int i = 0; i < 256; i++) {
line(new_histogramImage, Point(bin_wn * (i), hist_hn), Point(bin_wn * (i), hist_hn - histn[i]), Scalar(0), 1, 8, 0);
}
imwrite("Gray_Image.png", gray_image);
imwrite("newcontrast_Image.png", new_image);
imwrite("Histogram.png", new_histogramImage);
namedWindow("Image");
imshow("Image", img);
namedWindow("Gray_Image");
imshow("Gray_Image", gray_image);
namedWindow("newcontrast_Image");
imshow("newcontrast_Image", new_image);
namedWindow("New_Histogram");
imshow("New_Histogram", new_histogramImage);
namedWindow("Old_Histogram");
imshow("Old_Histogram", histImage);
waitKey(0);
return 0;
}
Here are the new and old histograms that I got as outputs
I found the solution for the question. Here I changed the lowest and highest point values as 100 and 240 and when using the values set those as decimals values.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int v = (int)gray_image.at<uchar>(y, x);
if (v >= 0 && v <= 100) {
output = int((5.0/ 100.0) * v);
}
else if (v > 100 && v <= 240) {
output = int(((245.0) / (140.0)) * (v - 100.0) + 5.0);
}
else if (v > 240 && v <= 255) {
output = int(((5.0) / (15.0)) * (v - 240.0) + 250.0);
}
new_image.at<uchar>(y, x) = (uchar)output;
}
}
I have this for() loop where I am randomizing the selection of slices of a picture, to display 16 slices of an image in a random order.
I'm picking those slices from an array and I have a variable that picks up what slice is going to be selected in the array.
The problem being that I'd think that the random function would be triggered for every frame, but it's triggered only once.
Here's the code :
void setup() {
size(720,720);
slices = new PImage[16];
slices[0] = loadImage("1.png");
slices[1] = loadImage("2.png");
slices[2] = loadImage("3.png");
slices[3] = loadImage("4.png");
slices[4] = loadImage("5.png");
slices[5] = loadImage("6.png");
slices[6] = loadImage("7.png");
slices[7] = loadImage("8.png");
slices[8] = loadImage("9.png");
slices[9] = loadImage("10.png");
slices[10] = loadImage("11.png");
slices[11] = loadImage("12.png");
slices[12] = loadImage("13.png");
slices[13] = loadImage("14.png");
slices[14] = loadImage("15.png");
slices[15] = loadImage("16.png");
frameRate(1);
}
void draw() {
for (int a = 0; a < 16; a++){
int rand = int(random(slices.length));
image(slices[rand],x,y,size,size);
x += size;
if (a % 4 == 3){
y += size;
x = 0;
}
}
It's dispalying the randomized slices only once and then I end up with a fix image. What I'd like to have is random slices appearing at every frame.
Thanks for your help !
You have 2 problems in your code.
First, you may not want to choose a random index.
This is because the same image could be chosen twice.
Instead, you could shuffle the array before drawing the images, like this:
for (int i = slices.length; i > 1; i--) {
//choose a random index for the i-th element to be swapped with
int j = (int)random(i);
//swap them
PImage temp = slices[j];
slices[j] = slices[i-1];
slices[i-1] = temp;
}
Second, the index is chosen on every frame, and the images are drawn, too, but you can't see it, because your code never resets y back to 0, meaning that they are below the screen.
You can fix this by adding
y = 0;
to the top or bottom of your draw().
Could it be because you've forgot to clear the screen (e.g. calling background()) (meaning once you've drawn an image it will stay rendered) ?
You could also make use of the for loop in setup to avoid repeating yourself:
int numSlices = 16;
PImage[] slices = new PImage[numSlices];
float x, y;
float size = 180;
void setup() {
size(720, 720);
for(int i = 0 ; i < numSlices; i++){
slices[i] = loadImage((i+1) + ".png");
}
frameRate(1);
}
void draw() {
background(255);
for (int a = 0; a < numSlices; a++) {
int rand = int(random(numSlices));
image(slices[rand], x, y, size, size);
x += size;
if (a % 4 == 3) {
y += size;
x = 0;
}
}
y = 0;
}
Additionally you could easily format your code (via CMD+T on OSX or Ctrl+T on Windows/Linux)
Update Kamakura (+1) correctly pointing out y not being reset to 0.
As a distraction I though't point you to IntList's shuffle() method:
int numSlices = 16;
PImage[] slices = new PImage[numSlices];
float x, y;
float size = 180;
IntList indices = new IntList();
void setup() {
size(720, 720);
for(int i = 0 ; i < numSlices; i++){
slices[i] = loadImage((i+1) + ".png");
indices.append(i);
}
frameRate(1);
}
void draw() {
background(255);
// shuffle list
indices.shuffle();
// reset y
y = 0;
for (int a = 0; a < numSlices; a++) {
int rand = indices.get(a);
image(slices[rand], x, y, size, size);
x += size;
if (a % 4 == 3) {
y += size;
x = 0;
}
}
}
Extra reason to play with it, other than a learning experience is that fact that it will be unlikely to get the same random index repeated.
Regarding splicing/shuffling, here's a modified version of the Load and Display example:
/**
* Load and Display
*
* Images can be loaded and displayed to the screen at their actual size
* or any other size.
*/
PImage img; // Declare variable "a" of type PImage
// shuffled image
PImage imgShuffled;
// list of indices to shuffle
IntList shuffleIndices = new IntList();
// configure image slicing rows/columns
int rows = 4;
int cols = 4;
// total sections
int numSections = rows * cols;
// image section dimensions
int sectionWidth;
int sectionHeight;
void setup() {
size(640, 360);
frameRate(1);
// The image file must be in the data folder of the current sketch
// to load successfully
img = loadImage("https://processing.org/examples/moonwalk.jpg"); // Load the image into the program
// calculate section dimensions
sectionWidth = img.width / cols;
sectionHeight = img.height / rows;
// allocate a separate image to copy shuffled pixels into
imgShuffled = createImage(img.width, img.height, RGB);
// populate image section indices
for(int i = 0 ; i < numSections; i++){
shuffleIndices.append(i);
}
}
void shuffleImage(){
// shuffle the list
shuffleIndices.shuffle();
// Ta-da!
println(shuffleIndices);
// loop through each section
for(int i = 0 ; i < numSections; i++){
// index to row, col conversion
int srcCol = i % cols;
int srcRow = i / cols;
// convert to pixel coordinates to copy from
int srcX = srcCol * sectionWidth;
int srcY = srcRow * sectionHeight;
// get random / shuffled index
int index = shuffleIndices.get(i);
// same row, col, to pixel conversion to copy to
int dstCol = index % cols;
int dstRow = index / cols;
int dstX = dstCol * sectionWidth;
int dstY = dstRow * sectionHeight;
// copy from original image to shuffled pixel coordinates
imgShuffled.copy(img,srcX,srcY,sectionWidth,sectionHeight,dstX,dstY,sectionWidth,sectionHeight);
}
}
void draw() {
shuffleImage();
// Displays the image at its actual size at point (0,0)
image(imgShuffled, 0, 0);
}
I'm trying to create a program to hide data in a image file. Data bits are hidden into last bit of every pixels blue value. First four pixels contain the length of following data bytes.
Everything works fine when I encrypt the data to image and then decrypt it without saving the image in between. However if I encrypt the data to an image and then save it and then open the file again and try to decrypt it, decryption fails since the values seem to have changed.
I wonder if there is something similar happening as with txt files where there is BOM containing byte order data prepended into the file?
The code works if I change the color c = crypted.pixels[pos + i];
to color c = original.pixels[pos + i]; in readByteAt function
and run the encrypting function first and then the decryption function.
This causes the code to run the decryption function on the just encrypted image still in program memory instead reading it from the file.
Any ideas on what causes this or how to prevent it are welcome!
here is the full (messy) code:
PImage original;
PImage crypted;
int imagesize;
boolean ready = false;
void setup() {
size(100, 100);
imagesize = width * height;
}
void draw() {
}
void encrypt()
{
original = loadImage("image.jpg");
original.loadPixels();
println("begin encrypt");
int pos = 0;
byte b[] = loadBytes("DATA.txt");
println("encrypting in image...");
int len = b.length;
println("len " + len);
writeByteAt((len >> (3*8)) & 0xFF, 0);
writeByteAt((len >> (2*8)) & 0xFF, 8);
writeByteAt((len >> (1*8)) & 0xFF, 16);
writeByteAt(len & 0xFF, 24);
pos = 32;
for (int i = 3; i < b.length; i++) {
int a = b[i] & 0xff;
print(char(a));
writeByteAt(a, pos);
pos += 8;
}
original.updatePixels();
println();
println("done");
original.save("encrypted.jpg");
}
void writeByteAt(int b, int pos)
{
println("writing " + b + " at " + pos);
for (int i = 0; i < 8; i++)
{
color c = original.pixels[pos + i];
int v = int(blue(c));
if ((b & (1 << i)) > 0)
{
v = v | 1;
} else
{
v = v & 0xFE;
}
original.pixels[pos+i] = color(red(c), green(c), v);
//original.pixels[pos+i] = color(255,255,255);
}
}
int readByteAt(int pos)
{
int b = 0;
for (int i = 0; i < 8; i++)
{
color c = crypted.pixels[pos + i];
int v = int(blue(c));
if ((v & 1) > 0)
{
b += (1 << i);
}
}
return b;
}
void decrypt()
{
crypted = loadImage("encrypted.jpg");
crypted.loadPixels();
println("begin decrypt");
int pos = 0;
PrintWriter output = createWriter("out.txt");
println("decrypting...");
int len = 0;
len += readByteAt(0) << 3*8;
len += readByteAt(8) << 2*8;
len += readByteAt(16) << 1*8;
len += readByteAt(24);
pos = 32;
if(len >= imagesize)
{
println("ERROR: DATA LENGTH OVER IMAGE SIZE");
return;
}
println(len);
while (pos < ((len+1)*8)) {
output.print(char(readByteAt(pos)));
print(char(readByteAt(pos)));
pos += 8;
}
output.flush(); // Writes the remaining data to the file
output.close();
println("\nDone");
}
void keyPressed()
{
if(key == 'e')
{
encrypt();
}
if(key == 'd')
{
decrypt();
}
}
I have two images. One has more green color and another one has better quality (it has right color). How can I improve the first one to have the similar color as the second one.I used the contrast enhancement as
//Contrast enhancement
for (int y = 0; y < rotated.rows; y++)
{
for (int x = 0; x < rotated.cols; x++)
{
for (int c = 0; c < 3; c++)
{
//"* Enter the alpha value [1.0-3.0]: "
//"* Enter the beta value [0-100]: ";
rotated.at<Vec3b>(y, x)[c] =
saturate_cast<uchar>(2.5*(rotated.at<Vec3b>(y, x)[c]) + 30);
}
}
}
It brightens the image. But I like to have similar color as the second one. What are the RGB values to change to have the second image's color.
For contrast enhancement you can use the equivalent of Matlab imadjust. You can find an OpenCV implementation here.
Applying imadjust with default parameters on each separate channel you get:
Here the full code:
#include <opencv2\opencv.hpp>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
void imadjust(const Mat1b& src, Mat1b& dst, int tol = 1, Vec2i in = Vec2i(0, 255), Vec2i out = Vec2i(0, 255))
{
// src : input CV_8UC1 image
// dst : output CV_8UC1 imge
// tol : tolerance, from 0 to 100.
// in : src image bounds
// out : dst image buonds
dst = src.clone();
tol = max(0, min(100, tol));
if (tol > 0)
{
// Compute in and out limits
// Histogram
vector<int> hist(256, 0);
for (int r = 0; r < src.rows; ++r) {
for (int c = 0; c < src.cols; ++c) {
hist[src(r, c)]++;
}
}
// Cumulative histogram
vector<int> cum = hist;
for (int i = 1; i < hist.size(); ++i) {
cum[i] = cum[i - 1] + hist[i];
}
// Compute bounds
int total = src.rows * src.cols;
int low_bound = total * tol / 100;
int upp_bound = total * (100 - tol) / 100;
in[0] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), low_bound));
in[1] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), upp_bound));
}
// Stretching
float scale = float(out[1] - out[0]) / float(in[1] - in[0]);
for (int r = 0; r < dst.rows; ++r)
{
for (int c = 0; c < dst.cols; ++c)
{
int vs = max(src(r, c) - in[0], 0);
int vd = min(int(vs * scale + 0.5f) + out[0], out[1]);
dst(r, c) = saturate_cast<uchar>(vd);
}
}
}
int main()
{
Mat3b img = imread("path_to_image");
vector<Mat1b> planes;
split(img, planes);
for (int i = 0; i < 3; ++i)
{
imadjust(planes[i], planes[i]);
}
Mat3b result;
merge(planes, result);
return 0;
}